经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
详解SpringBoot是如何整合JPA的
来源:jb51  时间:2021/6/21 9:36:31  对本文有异议

SpringBoot整合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:强大、方便、高效、复杂、绕弯子、全自动

一、导入依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>com.alibaba</groupId>
  4. <artifactId>fastjson</artifactId>
  5. <version>1.2.76</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.projectlombok</groupId>
  9. <artifactId>lombok</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.alibaba</groupId>
  13. <artifactId>druid</artifactId>
  14. <version>1.1.21</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-data-jpa</artifactId>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24.  
  25. <dependency>
  26. <groupId>mysql</groupId>
  27. <artifactId>mysql-connector-java</artifactId>
  28. <scope>runtime</scope>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-test</artifactId>
  33. <scope>test</scope>
  34. </dependency>
  35. </dependencies>

二、简单的CRUD

2.1 配置文件

  1. spring:
  2. datasource:
  3. username: root
  4. password: root
  5. url: jdbc:mysql://localhost:3306/shy
  6. driver-class-name: com.mysql.jdbc.Driver
  7. type: com.alibaba.druid.pool.DruidDataSource
  8. jpa:
  9. hibernate:
  10. #定义数据库表的生成策略 create 创建一个表 update 更新或者创建数据表
  11. ddl-auto: update
  12. #控制台显示sql语句
  13. show-sql: true
  14. server:
  15. 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.2 实体类

Shop:

  1. package com.shy.entity;
  2. import lombok.Data;
  3. import javax.persistence.*;
  4. @Data
  5. //使用jpa注解 配置映射关系
  6. @Entity//告诉jpa这是一个实体类 和数据表映射的类
  7. public class Shop{
  8. @Id//表明这是以一个主键
  9. @GeneratedValue(strategy = GenerationType.IDENTITY)//自增
  10. private Integer shopId;
  11.  
  12. @Column(length = 20)
  13. private String shopName;
  14.  
  15. private double price;
  16.  
  17. private Integer shopClassId;
  18.  
  19. private Integer num;
  20. }

ShopClass,商品类别

  1. package com.shy.entity;
  2. import lombok.Data;
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. @Data
  8. @Entity
  9. public class ShopClass {
  10. @Id
  11. @GeneratedValue(strategy = GenerationType.IDENTITY)
  12. private Integer shopClassId;
  13.  
  14. private String shopClassName;
  15. }

2.3 Dao层

编写dao继承JpaRepository类,泛型传入 要操作的实体类,和主键类型

  1. package com.example.dao;
  2. import com.shy.entity.Shop;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.stereotype.Repository;
  5.  
  6. /* 参数一 T :当前需要映射的实体
  7. * 参数二 ID :当前映射的实体中的OID(映射对象标识符,数据库主键)的类型*/
  8.  
  9. @Repository
  10. public interface ShopRepository extends JpaRepository<Shop,Integer> {
  11. /*
  12. * 我们在这里直接继承 JpaRepository
  13. * 这里面已经有很多现成的方法了
  14. * 这也是JPA的一大优点
  15. * 我们可以直接使用这些方法,包括其父类的好多方法。
  16. * */
  17. }

JpaRepository:

  1. package org.springframework.data.jpa.repository;
  2.  
  3. import java.util.List;
  4. import javax.persistence.EntityManager;
  5. import org.springframework.data.domain.Example;
  6. import org.springframework.data.domain.Sort;
  7. import org.springframework.data.repository.NoRepositoryBean;
  8. import org.springframework.data.repository.PagingAndSortingRepository;
  9. import org.springframework.data.repository.query.QueryByExampleExecutor;
  10.  
  11. @NoRepositoryBean
  12. public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
  13.  
  14. @Override
  15. List<T> findAll();// 查询所有实体
  16.  
  17. @Override
  18. List<T> findAll(Sort sort);// 查询所有实体并排序
  19.  
  20. @Override
  21. List<T> findAllById(Iterable<ID> ids);// 根据ID集合查询实体
  22.  
  23. @Override
  24. <S extends T> List<S> saveAll(Iterable<S> entities);// 保存并返回(修改后的)实体集合
  25.  
  26. void flush();// 提交事务
  27.  
  28. <S extends T> S saveAndFlush(S entity); // 保存实体并立即提交事务
  29.  
  30. <S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
  31.  
  32. @Deprecated
  33. default void deleteInBatch(Iterable<T> entities){deleteAllInBatch(entities);}
  34.  
  35. void deleteAllInBatch(Iterable<T> entities); // 批量删除实体集合
  36.  
  37. void deleteAllByIdInBatch(Iterable<ID> ids);
  38.  
  39. void deleteAllInBatch();// 批量删除所有实体
  40.  
  41. @Deprecated
  42. T getOne(ID id);// 根据ID查询实体
  43.  
  44. T getById(ID id);
  45.  
  46. @Override
  47. <S extends T> List<S> findAll(Example<S> example);// 查询与指定Example匹配的所有实体
  48.  
  49. @Override
  50. <S extends T> List<S> findAll(Example<S> example, Sort sort);// 查询与指定Example匹配的所有实体并排序
  51. }

2.4 service层

service:

  1. package com.shy.service;
  2.  
  3. import com.shy.entity.Shop;
  4. import com.shy.vo.ShopAndShopClassVo;
  5.  
  6. import java.util.List;
  7.  
  8. public interface ShopService {
  9. //查询所有商品
  10. List<Shop> findAll();
  11.  
  12. //增加商品
  13. Shop addShop(Shop shop);
  14.  
  15. //通过商品id修改商品名
  16. Shop updateShop();
  17.  
  18. //通过商品id删除商品
  19. void delShop(Integer id);
  20. }

Impl:

  1. package com.shy.service;
  2.  
  3. import com.shy.dao.ShopRepository;
  4. import com.shy.entity.Shop;
  5. import com.shy.vo.ShopAndShopClassVo;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7.  
  8. import org.springframework.data.domain.Sort;
  9. import org.springframework.stereotype.Service;
  10.  
  11. import java.util.List;
  12.  
  13. @Service
  14. public class ShopServiceImpl implements ShopService{
  15. @Autowired
  16. private ShopRepository shopRepository;
  17.  
  18. @Override
  19. public List<Shop> findAll() {
  20. return shopRepository.findAll();
  21. }
  22.  
  23. @Override
  24. public Shop addShop(Shop shop) {
  25. shop.setPrice(333);
  26. shop.setShopClassId(3);
  27. shop.setNum(30);
  28. shop.setShopName("耳机");
  29. return shopRepository.save(shop);
  30. }
  31.  
  32. @Override
  33. public Shop updateShop() {
  34. Shop shop = new Shop();
  35. shop.setShopId(11);
  36. shop.setShopName("平板");
  37. shop.setShopClassId(3);
  38. shop.setNum(40);
  39. return shopRepository.save(shop);
  40. }
  41.  
  42. @Override
  43. public void delShop(Integer id) {
  44. shopRepository.deleteById(id);
  45. System.out.println("删除成功");
  46. }
  47. }

2.5 controller

  1. package com.shy.controller;
  2.  
  3. import com.alibaba.fastjson.JSON;
  4. import com.shy.entity.Shop;
  5. import com.shy.service.ShopService;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.PathVariable;
  9. import org.springframework.web.bind.annotation.RestController;
  10. @RestController
  11. public class ShopController {
  12. @Autowired
  13. private ShopService shopService;
  14.  
  15. @GetMapping("/list")
  16. public String findAll(){
  17. return JSON.toJSONString(shopService.findAll());
  18. }
  19.  
  20. @GetMapping("/save")
  21. public String save(Shop shop){
  22. return JSON.toJSONString(shopService.addShop(shop));
  23. }
  24.  
  25. @GetMapping("/saveAndFlush")
  26. public String saveAndFlush(){
  27. return JSON.toJSONString(shopService.updateShop());
  28. }
  29.  
  30. @GetMapping("/delShop/{id}")
  31. public void delShop(@PathVariable Integer id){
  32. shopService.delShop(id);
  33. }
  34.  
  35. }
  36.  

全程用postman测试

三、自定义SQL

在ShopRepository中添加

  1. //使用原生sql需要加上,nativeQuery = true
  2. //?1代表第一个参数
  3. @Query(value="select * from shop where shop.price = ?1",nativeQuery = true)
  4. Shop findByPrice(Double price);
  5.  
  6. //修改商品,@Modifying+@Query执行更新操作,serviceImpl不要忘记加上,要使用hql的话,需要把entity别名删掉
  7. @Transactional//设计修改表的操作需要开启事务支持
  8. @Modifying//这个注解只支持返回值为int/Integer
  9. @Query("update Shop s set s.shopName = ?1 where s.shopId = ?2")
  10. int updateshop2(String name,Integer shopId);

service:

  1. //通过价格查询商品
  2. Shop findByPrice(Double price);
  3.  
  4. //修改商品名原生sql方法
  5. int updateshop2(String name,Integer shopId);

Impl:

  1. @Override
  2. public Shop findByPrice(Double price) {
  3. return shopRepository.findByPrice(price);
  4. }
  5.  
  6. @Override
  7. public int updateshop2(String name, Integer shopId) {
  8. return shopRepository.updateshop2(name, shopId);
  9. }

controller:

  1. @GetMapping("/listPrice/{price}")
  2. public String findByPrice(@PathVariable Double price){
  3. return JSON.toJSONString(shopService.findByPrice(price));
  4. }
  5.  
  6. @GetMapping("/saveAndFlush2/{id}/{name}")
  7. public String saveAndFlush2(@PathVariable(value = "id") Integer shopId,
  8. @PathVariable String name){
  9. return shopService.updateshop2(name, shopId)>0?"修改成功":"修改失败";
  10. }

四、分页查询

Pageable 是 Spring 封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则。

Spring Data JPA 已经帮我们内置了分页功能,在查询的方法中,需要传入参数 Pageable,当查询中有多个参数的时候 Pageable 建议作为最后一个参数传入,

Pageable使用的时候需要传入页数、每页条数和排序规则,排序规则可省略

service:

  1. /**
  2. * 分页查询
  3. * @param pageNo 第几页
  4. * @param pageSize 每页有多少条数据
  5. * @param pageable Spring 封装的分页实现类
  6. * @return 数据
  7. */
  8. Page<Shop> pageShop(Integer pageNo,Integer pageSize,Pageable pageable);

Impl:

  1. @Override
  2. public Page<Shop> pageShop(Integer pageNo, Integer pageSize, Pageable pageable) {
  3. //注意排序这找的是实体类中的字段,不是数据库里的
  4. //分页页码从0开始
  5. pageable = PageRequest.of(pageNo,pageSize, Sort.Direction.DESC, "shopId");
  6. return shopRepository.findAll(pageable);
  7. }

controller:

  1. @GetMapping("/pageShop/{pageNo}/{pageSize}")
  2. public String pageShop(@PathVariable Integer pageNo,
  3. @PathVariable Integer pageSize,Pageable pageable){
  4. return JSON.toJSONString(shopService.pageShop(pageNo, pageSize, pageable));
  5. }

五、连表查询

VO(value object)值对象

  • 通常用于业务层之间的数据传递,仅仅包含数据而已
  • View object:视图对象

接受页面传递来的对象,封装对象

将业务处理完成的对象,封装成页面要用的数据

创建ShopAndShopClassVo用来接收连表查询后的结果

entity,这里的有参构造必须加,要往里赋值

  1. package com.shy.entity;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @AllArgsConstructor
  7. @NoArgsConstructor
  8. public class ShopAndShopClassVo {
  9. private String shopName;
  10. private double price;
  11. private String shopClassName;
  12. }

ShopRepository:

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

JPQL进行查询,它的特征就是与原生SQL语句类似,完全面向对象,通过类名和属性访问,而不是表名和表属性

service:

  1. //连表查询
  2. List<ShopAndShopClassVo> findShopInfo(String shopClassName);

Impl:

  1. @Override
  2. public List<ShopAndShopClassVo> findShopInfo(String shopClassName) {
  3. return shopRepository.findShopInfo(shopClassName);
  4. }

controller:

  1. @GetMapping("/andFind/{name}")
  2. public String findShopInfo(@PathVariable("name") String shopClassName){
  3. return JSON.toJSONString(shopService.findShopInfo(shopClassName));
  4. }

六、分组查询

接收数据的另一种写法,创建一个结果集的接口来接收连表查询后的结果

定义一个结果集的接口类,接口类的内容来自于商品表和商品类别表。

entity:

  1. package com.shy.entity;
  2.  
  3. public interface GroupShop {
  4. String getNum();
  5. String getShopClassName();
  6. }

在运行中 Spring 会给接口(GroupShop)自动生产一个代理类来接收返回的结果,代码中使用 getXX 的形式来获取。

ShopRepository:

  1. //分组查询
  2. @Query("select count(s.shopName) as 商品数量,sc.shopClassName as 类别名称 from Shop s,ShopClass sc where s.shopClassId=sc.shopClassId group by s.shopClassId")
  3. List<GroupShop> groupShop();

service:

  1. //分组查询
  2. List<GroupShop> groupShop();

Impl:

  1. @Override
  2. public List<GroupShop> groupShop() {
  3. return shopRepository.groupShop();
  4. }

controller:

  1. @GetMapping("/groupShop")
  2. public String groupShop(){
  3. return JSON.toJSONString(shopService.groupShop());
  4. }

七、与mybatis对比

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

到此这篇关于详解SpringBoot如何是整合JPA的的文章就介绍到这了,更多相关SpringBoot整合JPA内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号