SpringBoot整合SpringDataJPA

目录

  • SpringBoot整合JPA
    • JPA & Spring Data JPA
    • Hibernate & JPA
      • 1、JPA
      • 2、JPA & Hibernate 关系
    • Hibernate VS Mybatis
    • 一、导入依赖
      • 二、简单的CRUD
        • 1、配置文件
          • 2、实体类
            • 3、Dao层
              • 4、service层
                • 5、controller
                • 三、自定义SQL
                  • 四、分页查询
                    • 五、连表查询
                      • 六、分组查询
                        • 七、与mybatis对比
                          • 总结

                            SpringBoot整合JPA 使用数据库是开发基本应用的基础,借助于开发框架,我们已经不用编写原始的访问数据库的代码,也不用调用JDBC(Java Data Base Connectivity)或者连接池等诸如此类的被称作底层的代码,我们将从更高的层次上访问数据库,这在Springboot中更是如此,本章我们将详细介绍在Springboot中使用 Spring Data JPA 来实现对数据库的操作。

                            JPA & Spring Data JPA
                            JPA是Java Persistence API的简称,中文名Java持久层API,是Sun官方提出的Java持久化规范.
                            其设计目标主要是为了简化现有的持久化开发工作和整合ORM技术。
                            JPA使用XML文件或注解(JDK 5.0或更高版本)来描述对象-关联表的映射关系,能够将运行期的实体对象持久化到数据库,它为Java开发人员提供了一种ORM工具来管理Java应用中的关系数据。
                            简单地说,JPA就是为POJO(Plain Ordinary Java Object)提供持久化的标准规范,即将Java的普通对象通过对象关系映射(Object-Relational Mapping,ORM)持久化到数据库中。
                            由于JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,因而具有易于使用、伸缩性强等优点。
                            Spring Data JPA 是 Spring 基于 Spring Data 框架、在JPA 规范的基础上开发的一个框架,使用 Spring Data JPA 可以极大地简化JPA 的写法,可以在几乎不用写实现的情况下实现对数据库的访问和操作,除了CRUD外,还包括分页和排序等一些常用的功能。
                            Spring Data JPA 还提供了对分页查询、自定义SQL、查询指定N条记录、联表查询等功能的支持
                            JPA不是一种新的ORM框架,它的出现只是用于规范现有的ORM技术,它不能取代现有的Hibernate、TopLink等框架。相反,在采用JPA开发时,我们将仍将使用到这些ORM框架,只是此时开发出来的应用不再依赖于某个持久化提供商。应用可以在不修改代码的情况下在任何JPA环境下运行,真正做到低耦合,可扩展的程序设计。

                            Hibernate & JPA

                            1、JPA 全称Java Persistence API,通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
                            JPA的出现有两个原因:
                            其一,简化现有Java EE和Java SE应用的对象持久化的开发工作;
                            其二,Sun希望整合对ORM技术,实现持久化领域的统一。
                            JPA提供的技术:
                            1)ORM映射元数据:JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
                            2)JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
                            3)查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

                            2、JPA & Hibernate 关系 JPA是规范,Hibernate是框架,JPA是持久化规范,而Hibernate实现了JPA。

                            Hibernate VS Mybatis
                            Mybatis:小巧、方便、高效、简单、直接、半自动
                            Hibernate:强大、方便、高效、复杂、绕弯子、全自动

                            一、导入依赖
                            com.alibabafastjson1.2.76org.projectlomboklombokcom.alibabadruid1.1.21org.springframework.bootspring-boot-starter-data-jpaorg.springframework.bootspring-boot-starter-webmysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-starter-testtest


                            二、简单的CRUD
                            1、配置文件
                            spring:datasource:username: rootpassword: rooturl: jdbc:mysql://localhost:3306/shydriver-class-name: com.mysql.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcejpa:hibernate:#定义数据库表的生成策略 create 创建一个表 update 更新或者创建数据表ddl-auto: update#控制台显示sql语句show-sql: trueserver:port: 80

                            其中,spring.jpa.hibernate.ddl-auto 参数用来配置是否开启自动更新数据库表结构,可取create、create-drop、update、validate、none五个值。
                            • create 每次加载hibernate时,先删除已存在的数据库表结构再重新生成;
                            • create-drop 每次加载hibernate时,先删除已存在的数据库表结构再重新生成,并且当 sessionFactory关闭时自动删除生成的数据库表结构;
                            • update 只在第一次加载hibernate时自动生成数据库表结构,以后再次加载hibernate时根据model类自动更新表结构;
                            • validate 每次加载hibernate时,验证数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
                            • none 关闭自动更新

                            2、实体类
                            Shop:
                            package com.shy.entity; import lombok.Data; import javax.persistence.*; @Data//使用jpa注解 配置映射关系@Entity//告诉jpa这是一个实体类 和数据表映射的类public class Shop{@Id//表明这是以一个主键@GeneratedValue(strategy = GenerationType.IDENTITY)//自增private Integer shopId; @Column(length = 20)private String shopName; private double price; private Integer shopClassId; private Integer num; }

                            ShopClass,商品类别
                            package com.shy.entity; import lombok.Data; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Data@Entitypublic class ShopClass {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer shopClassId; private String shopClassName; }


                            3、Dao层
                            编写dao继承JpaRepository类,泛型传入 要操作的实体类,和主键类型
                            package com.example.dao; import com.shy.entity.Shop; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; /* 参数一 T :当前需要映射的实体 * 参数二 ID :当前映射的实体中的OID(映射对象标识符,数据库主键)的类型*/@Repositorypublic interface ShopRepository extends JpaRepository {/** 我们在这里直接继承 JpaRepository* 这里面已经有很多现成的方法了* 这也是JPA的一大优点* 我们可以直接使用这些方法,包括其父类的好多方法。* */}

                            JpaRepository:
                            package org.springframework.data.jpa.repository; import java.util.List; import javax.persistence.EntityManager; import org.springframework.data.domain.Example; import org.springframework.data.domain.Sort; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.QueryByExampleExecutor; @NoRepositoryBeanpublic interface JpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor { @Override List findAll(); // 查询所有实体 @Override List findAll(Sort sort); // 查询所有实体并排序 @Override List findAllById(Iterable ids); // 根据ID集合查询实体 @OverrideList saveAll(Iterable entities); // 保存并返回(修改后的)实体集合 void flush(); // 提交事务S saveAndFlush(S entity); // 保存实体并立即提交事务List saveAllAndFlush(Iterable entities); @Deprecated default void deleteInBatch(Iterable entities){deleteAllInBatch(entities); } void deleteAllInBatch(Iterable entities); // 批量删除实体集合 void deleteAllByIdInBatch(Iterable ids); void deleteAllInBatch(); // 批量删除所有实体 @Deprecated T getOne(ID id); // 根据ID查询实体 T getById(ID id); @OverrideList findAll(Example example); // 查询与指定Example匹配的所有实体 @OverrideList findAll(Example example, Sort sort); // 查询与指定Example匹配的所有实体并排序}


                            4、service层
                            service:
                            package com.shy.service; import com.shy.entity.Shop; import com.shy.vo.ShopAndShopClassVo; import java.util.List; public interface ShopService {//查询所有商品List findAll(); //增加商品Shop addShop(Shop shop); //通过商品id修改商品名Shop updateShop(); //通过商品id删除商品void delShop(Integer id); }

                            Impl:
                            package com.shy.service; import com.shy.dao.ShopRepository; import com.shy.entity.Shop; import com.shy.vo.ShopAndShopClassVo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import java.util.List; @Servicepublic class ShopServiceImpl implements ShopService{@Autowiredprivate ShopRepository shopRepository; @Overridepublic List findAll() {return shopRepository.findAll(); }@Overridepublic Shop addShop(Shop shop) {shop.setPrice(333); shop.setShopClassId(3); shop.setNum(30); shop.setShopName("耳机"); return shopRepository.save(shop); }@Overridepublic Shop updateShop() {Shop shop = new Shop(); shop.setShopId(11); shop.setShopName("平板"); shop.setShopClassId(3); shop.setNum(40); return shopRepository.save(shop); }@Overridepublic void delShop(Integer id) {shopRepository.deleteById(id); System.out.println("删除成功"); }}


                            5、controller
                            package com.shy.controller; import com.alibaba.fastjson.JSON; import com.shy.entity.Shop; import com.shy.service.ShopService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestControllerpublic class ShopController {@Autowiredprivate ShopService shopService; @GetMapping("/list")public String findAll(){return JSON.toJSONString(shopService.findAll()); }@GetMapping("/save")public String save(Shop shop){return JSON.toJSONString(shopService.addShop(shop)); }@GetMapping("/saveAndFlush")public String saveAndFlush(){return JSON.toJSONString(shopService.updateShop()); }@GetMapping("/delShop/{id}")public void delShop(@PathVariable Integer id){shopService.delShop(id); }}

                            全程用postman测试

                            三、自定义SQL 在ShopRepository中添加
                            //使用原生sql需要加上,nativeQuery = true//?1代表第一个参数@Query(value="https://www.it610.com/article/select * from shop where shop.price = ?1",nativeQuery = true)Shop findByPrice(Double price); //修改商品,@Modifying+@Query执行更新操作,serviceImpl不要忘记加上,要使用hql的话,需要把entity别名删掉@Transactional//设计修改表的操作需要开启事务支持@Modifying//这个注解只支持返回值为int/Integer@Query("update Shop s set s.shopName = ?1 where s.shopId = ?2")int updateshop2(String name,Integer shopId);

                            service:
                            //通过价格查询商品Shop findByPrice(Double price); //修改商品名原生sql方法int updateshop2(String name,Integer shopId);

                            Impl:
                            @Overridepublic Shop findByPrice(Double price) {return shopRepository.findByPrice(price); } @Overridepublic int updateshop2(String name, Integer shopId) {return shopRepository.updateshop2(name, shopId); }

                            controller:
                            @GetMapping("/listPrice/{price}")public String findByPrice(@PathVariable Double price){return JSON.toJSONString(shopService.findByPrice(price)); } @GetMapping("/saveAndFlush2/{id}/{name}")public String saveAndFlush2(@PathVariable(value = "https://www.it610.com/article/id") Integer shopId,@PathVariable String name){return shopService.updateshop2(name, shopId)>0?"修改成功":"修改失败"; }


                            四、分页查询 Pageable 是 Spring 封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则。
                            Spring Data JPA 已经帮我们内置了分页功能,在查询的方法中,需要传入参数 Pageable,当查询中有多个参数的时候 Pageable 建议作为最后一个参数传入,
                            Pageable使用的时候需要传入页数、每页条数和排序规则,排序规则可省略
                            service:
                            /*** 分页查询* @param pageNo 第几页* @param pageSize 每页有多少条数据* @param pageable Spring 封装的分页实现类* @return 数据*/Page pageShop(Integer pageNo,Integer pageSize,Pageable pageable);

                            Impl:
                            @Overridepublic Page pageShop(Integer pageNo, Integer pageSize, Pageable pageable) {//注意排序这找的是实体类中的字段,不是数据库里的//分页页码从0开始pageable = PageRequest.of(pageNo,pageSize, Sort.Direction.DESC, "shopId"); return shopRepository.findAll(pageable); }

                            controller:
                            @GetMapping("/pageShop/{pageNo}/{pageSize}")public String pageShop(@PathVariable Integer pageNo,@PathVariable Integer pageSize,Pageable pageable){return JSON.toJSONString(shopService.pageShop(pageNo, pageSize, pageable)); }


                            五、连表查询 VO(value object)值对象
                            • 通常用于业务层之间的数据传递,仅仅包含数据而已
                            • View object:视图对象
                            接受页面传递来的对象,封装对象
                            将业务处理完成的对象,封装成页面要用的数据
                            创建ShopAndShopClassVo用来接收连表查询后的结果
                            entity,这里的有参构造必须加,要往里赋值
                            package com.shy.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data@AllArgsConstructor@NoArgsConstructorpublic class ShopAndShopClassVo {private String shopName; private double price; private String shopClassName; }

                            ShopRepository:
                            //连表查询@Query("select new com.shy.vo.ShopAndShopClassVo(s.shopName,s.price,sc.shopClassName) from Shops,ShopClass sc " +"where s.shopClassId=sc.shopClassId and sc.shopClassName=?1")List findShopInfo(String shopClassName);

                            JPQL进行查询,它的特征就是与原生SQL语句类似,完全面向对象,通过类名和属性访问,而不是表名和表属性
                            service:
                            //连表查询List findShopInfo(String shopClassName);

                            Impl:
                            @Overridepublic List findShopInfo(String shopClassName) {return shopRepository.findShopInfo(shopClassName); }

                            controller:
                            @GetMapping("/andFind/{name}")public String findShopInfo(@PathVariable("name") String shopClassName){return JSON.toJSONString(shopService.findShopInfo(shopClassName)); }


                            六、分组查询 接收数据的另一种写法,创建一个结果集的接口来接收连表查询后的结果
                            定义一个结果集的接口类,接口类的内容来自于商品表和商品类别表。
                            entity:
                            package com.shy.entity; public interface GroupShop {String getNum(); String getShopClassName(); }

                            在运行中 Spring 会给接口(GroupShop)自动生产一个代理类来接收返回的结果,代码中使用 getXX 的形式来获取。
                            ShopRepository:
                            //分组查询@Query("select count(s.shopName) as 商品数量,sc.shopClassName as 类别名称 from Shop s,ShopClass sc where s.shopClassId=sc.shopClassId group by s.shopClassId")List groupShop();

                            service:
                            //分组查询List groupShop();

                            Impl:
                            @Overridepublic List groupShop() {return shopRepository.groupShop(); }

                            controller:
                            @GetMapping("/groupShop")public String groupShop(){return JSON.toJSONString(shopService.groupShop()); }


                            七、与mybatis对比
                            • jpa是对象与对象之间的映射,而mybatis是对象和结果集的映射
                            • jpa移植性比较好,不用关心用什么数据库,因为mybatis自由写sql语句,所以当项目移植的时候还需要改sql。
                            • 修改字段时JPA更简单,mybatis需要修改一堆的xml,mapper等文件很麻烦。
                            • mybatis自定义sql,比较灵活,也可以写复杂的sql,JPA只适合简单的单表sql

                            总结 mybatis和JPA各有优势,如果sql简单,则jpa使用效率更高,如果sql较复杂,需要自定义,则使用mybatis更加顺手。
                            【SpringBoot整合SpringDataJPA】本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

                              推荐阅读