【SpringBoot整合系列】SpringBoot整合JPA

news/2024/10/18 8:33:23/

目录

  • 前期回顾
    • ORM解决方案
  • JPA
    • 简介
    • JPA的组成技术
      • ORM映射元数据
      • Java持久化API
      • 查询语言(JPQL)
    • JPA的优势
    • JPA的缺点
  • Spring Data JPA
    • Spring Data JPA简介
    • Spring Data 家族
    • Spring Data JPA、JPA和其他框架之间的关系
  • SpringBoot整合JPA
    • JPA的核心注解
    • 1.依赖
    • 2.添加配置
    • 3.实体类
    • 4.创建数据访问层接口继承自JpaRepository<T, ID>接口
    • 5.添加用户业务实现类
    • 6.测试
      • 测试添加
      • 测试修改
      • 测试简单查询
      • 测试删除(简单和批量删除)
  • SpringData JPA的查询
    • 第一种查询方式:约定方法名
      • 示例
    • 第二种查询方式:使用JPQL查询
      • 示例
    • 第三种查询方式:使用Exampler查询
      • 示例
    • 第四种查询方式:使用原生SQL查询
      • 示例
    • 分页查询:
      • 方式1:PagingAndSortingRepository分页接口,适用于简单的分页查询;
        • 示例1
        • 示例2:
      • 方式2:Specification。自定义方法findAll,适用于动态分页查询;
        • 示例
  • SpringData JPA配置多数据源
    • 同源数据库的多源支持
    • 异构数据库多源支持
      • 示例
    • 多数据源使用案例
      • 1.依赖
      • 2.配置
    • 3.实体类
    • 4.配置类
    • 5.业务逻辑层
    • 6.测试

前期回顾

ORM解决方案

框架名称所属公司适用场合
Hibernate创始人:Gavin King
公司:JBOSS 所有
适用与需求变化不多的中小型项目中,比如后台管理系统
MybatisApache社区适用于表关联较多的项目,持续维护开发迭代较快的项目,需求变化较多的项目,如互联网项目
Mybatis-Plus苞米豆社区, 为猿类崛起而生MyBatis-Plus是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
Spring Data JPASpring的母公司是VMware传统项目或者关系模型较为清晰稳定的项目,建议JPA

JPA

简介

  • JPA是Java Persistence API的简称,中文名Java持久层API,是Sun公司在JDK5.0后提出的一套基于ORM的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。
  • Sun公司引入新的JPA ORM规范出于两个原因:
    • 其一,简化现有Java EE和Java SE应用开发工作;
    • 其二,结束Hibernate、TopLink、JDO等ORM框架各自为营的局面。Sun公司希望整合ORM技术,实现天下归一;
  • JPA是在吸收现有ORM框架的基础上发展而来,具有易于使用,伸缩性强等优点。
  • 由于JPA只是一个规范,它本身不执行任何操作。 它需要一个实现。 因此,像Hibernate,TopLink和iBatis这样的ORM工具实现了JPA数据持久性规范。
  • JSR 338,详细内容可参考:https://github.com/javaee/jpa-spec)

JPA的组成技术

ORM映射元数据

  • JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;

Java持久化API

  • 用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。

查询语言(JPQL)

  • 这是持久化操作中很重要的一个方面,通过面向对象的查询语言查询数据,避免程序和SQL语句紧密耦合。

JPA的优势

  1. 简化开发:Jpa提供了一种面向对象的方式来进行数据库操作,开发人员可以使用Java对象来表示数据库表和记录,而不需要编写复杂的SQL语句。这样可以大大简化开发过程,提高开发效率。
  2. 高度抽象:Jpa提供了一套高度抽象的API,隐藏了底层数据库的细节,开发人员可以更加专注于业务逻辑的实现,而不需要关注数据库的具体实现细节。这样可以降低开发的复杂性,提高代码的可维护性。
  3. 数据库支持:Jpa支持多种数据库,开发人员可以在不同的数据库之间切换,而不需要修改大量的代码。这样可以提高系统的灵活性和可扩展性。
  4. 自动化的事务管理:Jpa提供了自动化的事务管理机制,开发人员可以使用注解来标识事务的边界,Jpa会自动处理事务的提交和回滚。这样可以简化事务管理的代码,提高系统的稳定性和可靠性。

JPA的缺点

  1. 学习成本较高:Jpa是一种复杂的技术,需要开发人员具备一定的数据库和ORM(对象关系映射)的知识。对于初学者来说,学习和掌握Jpa可能需要一定的时间和精力。
  2. 性能问题:由于Jpa是一种高度抽象的技术,它会对数据库的访问和操作进行一定的封装和转换,这可能会导致一定的性能损失。在对性能要求较高的场景下,可能需要使用原生的SQL语句来进行数据库操作。
  3. 灵活性受限:Jpa提供了一套标准的API,开发人员需要按照这套API来进行开发,这可能会限制一些特定的需求和场景。在一些复杂的业务场景下,可能需要使用原生的SQL语句或其他ORM框架来实现。

Spring Data JPA

Spring Data JPA简介

  • 官网:https://spring.io/projects/spring-data-jpa
  • Spring Data JPA是Spring Data家族的一部分,可以轻松实现基于JPA的存储库。 此模块处理对基于JPA的数据访问层的增强支持。 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。
  • Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展。
  • 在相当长的一段时间内,实现应用程序的数据访问层一直很麻烦。 必须编写太多样板代码来执行简单查询以及执行分页和审计。 Spring Data JPA旨在通过减少实际需要的工作量来显著改善数据访问层的实现。

Spring Data 家族

  • Spring Data的官网:http://projects.spring.io/spring-data/
  • Spring Data是Spring的一个子项目,旨在统一和简化各类型的持久化存储方式,而不拘泥于是关系型数据库还是NoSQL数据库
  • Spring Data 的使命是给各种数据访问提供统一的编程接口,从而简化开发人员的代码,提高开发效率。
  • 无论是哪种持久化存储方式,数据库访问对象都会提供对对象的增加、删除、修改和查询的方法,以及排序和分页方法等。
    在这里插入图片描述

Spring Data JPA、JPA和其他框架之间的关系

  • JPA是一套规范,而不是具体的ORM框架。
  • Hibernate、TopLink等是JPA规范的具体实现,这样的好处是开发者可以面向JPA规范进行持久层的开发,而底层的实现则是可以切换的。
  • Spring Data Jpa则是在JPA之上添加另一层抽象,极大地简化持久层开发及ORM框架切换的成本
    在这里插入图片描述

SpringBoot整合JPA

JPA的核心注解

在这里插入图片描述在这里插入图片描述

1.依赖

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

2.添加配置

server:port: 9999
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456type: com.zaxxer.hikari.HikariDataSourcejpa:hibernate:ddl-auto: updatenaming:physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImplshow-sql: truedatabase-platform: org.hibernate.dialect.MySQL5InnoDBDialect

3.实体类

java">package cn.smbms.pojo;import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;import javax.persistence.*;
import java.util.Date;/*** @author: zjl* @datetime: 2024/4/23* @desc:*/
@Data
@Table(name = "smbms_user")
@Entity
public class User {@Id@Column(name = "id")@GeneratedValue(strategy = GenerationType.AUTO)private Integer id;@Column(name = "userCode")private String userCode;private String userName;private String userPassword;private Integer gender;@DateTimeFormat(pattern = "yyyy-MM-dd")private Date birthday;@Column(name = "phone",nullable = false)private String phone;private String address;@Column(name = "userRole",updatable = false)private Integer userRole;private Integer createdBy;@DateTimeFormat(pattern = "yyyy-MM-dd")private Date creationDate;private Integer modifyBy;@DateTimeFormat(pattern = "yyyy-MM-dd")private Date modifyDate;
}

4.创建数据访问层接口继承自JpaRepository<T, ID>接口

  • JpaRepository拥有基本CRUD功能以及分页功能
    在这里插入图片描述

  • JpaRepository继承自PagingAndSortingRepository。
    在这里插入图片描述

    • 分页接口和实现类
      • Pageable 是Spring Data库中定义的一个接口,用于构造翻页查询,是所有分页相关信息的一个抽象,通过该接口,我们可以得到和分页相关所有信息(例如pageNumber、pageSize等),这样,Jpa就能够通过Pageable参数来得到一个带分页信息的Sql语句
      • PageRequest:Pageable接口的实现类
      • Page接口:用于储存查询的结果集
    • 排序
  • 泛型 T 为任意实体对象,ID为主键的数据类型

java">public interface UserRepository extends JpaRepository<User, Integer> {
}

5.添加用户业务实现类

java">@Service
public class UserService {@Resourceprivate UserRepository userRepository;public User saveOrUpdate(User user){User saveUser = userRepository.save(user);return saveUser;}
}

6.测试

测试添加

  • 因为设置了主键ID的策略为自增,因此不用传ID就会执行添加操作。
  • 也可以传一个不存在的ID,也会执行新增操作,但是主键并不是自定义的主键值,而是自增的主键值
java">@SpringBootTest
class JpabootApplicationTests {@Resourceprivate UserService userService;@Testvoid saveOrUpdate() {User user = new User();user.setUserName("薇恩");user.setUserCode("VN");user.setAddress("下路");user.setPhone("180xxxx4568");user.setUserRole(3);User saveResult = userService.saveOrUpdate(user);System.out.println(saveResult);}
}
  • 执行结果如下:
    java">Hibernate: select next_val as id_val from hibernate_sequence for update
    Hibernate: update hibernate_sequence set next_val= ? where next_val=?
    Hibernate: insert into smbms_user (address, birthday, createdBy, creationDate, gender, modifyBy, modifyDate, phone, userCode, userName, userPassword, userRole, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    User(id=31, userCode=VN, userName=暗夜射手, userPassword=null, gender=null, birthday=null, phone=180xxxx4568, address=下路, userRole=3, createdBy=null, creationDate=null, modifyBy=null, modifyDate=null)
    

如果不传phone的话,会报错,提示phone属性不能为空

测试修改

  • 传一个已存在的ID,会触发修改,若属性为空,会将对应的字段值也修改为空,因此需要特别注意
java">    @Testvoid saveOrUpdate() {User user = new User();user.setId(31);user.setUserName("暗夜射手");user.setUserCode("VN");//user.setAddress("下路");user.setPhone("180xxxx4568");user.setUserRole(3);User saveResult = userService.saveOrUpdate(user);System.out.println(saveResult);}
  • 因为userRole设置了updatable = false,因此数据中这个字段的值还会是3,而不是2
  • 执行结果如下:
    java">Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.createdBy as createdb4_0_0_, user0_.creationDate as creation5_0_0_, user0_.gender as gender6_0_0_, user0_.modifyBy as modifyby7_0_0_, user0_.modifyDate as modifyda8_0_0_, user0_.phone as phone9_0_0_, user0_.userCode as usercod10_0_0_, user0_.userName as usernam11_0_0_, user0_.userPassword as userpas12_0_0_, user0_.userRole as userrol13_0_0_ from smbms_user user0_ where user0_.id=?
    Hibernate: update smbms_user set address=?, birthday=?, createdBy=?, creationDate=?, gender=?, modifyBy=?, modifyDate=?, phone=?, userCode=?, userName=?, userPassword=? where id=?
    User(id=31, userCode=VN, userName=暗夜射手, userPassword=null, gender=null, birthday=null, phone=180xxxx4568, address=null, userRole=3, createdBy=null, creationDate=null, modifyBy=null, modifyDate=null)
    

测试简单查询

service层

java">    public User findUserById(Integer id){return userRepository.findById(id).get();}

测试

java">    @Testvoid findUserById() {User user = userService.findUserById(1);System.out.println(user);}

执行结果如下:

java">Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.createdBy as createdb4_0_0_, user0_.creationDate as creation5_0_0_, user0_.gender as gender6_0_0_, user0_.modifyBy as modifyby7_0_0_, user0_.modifyDate as modifyda8_0_0_, user0_.phone as phone9_0_0_, user0_.userCode as usercod10_0_0_, user0_.userName as usernam11_0_0_, user0_.userPassword as userpas12_0_0_, user0_.userRole as userrol13_0_0_ from smbms_user user0_ where user0_.id=?
User(id=1, userCode=admin, userName=系统管理员, userPassword=0000aaaa, gender=1, birthday=1983-10-10 00:00:00.0, phone=13688889999, address=北京市海淀区成府路207, userRole=1, createdBy=1, creationDate=2013-03-21 16:52:07.0, modifyBy=null, modifyDate=null)

测试删除(简单和批量删除)

service层

java">    public void delete() {userRepository.deleteById(27);User user1 = userRepository.findById(28).get();User user2 = userRepository.findById(29).get();User user3 = userRepository.findById(30).get();List<User> users = new ArrayList<>(Arrays.asList(user1,user2,user3));userRepository.deleteInBatch(users);}

测试

java">    @Testvoid delete() {userService.delete();}

执行结果如下:

java">Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.createdBy as createdb4_0_0_, user0_.creationDate as creation5_0_0_, user0_.gender as gender6_0_0_, user0_.modifyBy as modifyby7_0_0_, user0_.modifyDate as modifyda8_0_0_, user0_.phone as phone9_0_0_, user0_.userCode as usercod10_0_0_, user0_.userName as usernam11_0_0_, user0_.userPassword as userpas12_0_0_, user0_.userRole as userrol13_0_0_ from smbms_user user0_ where user0_.id=?
Hibernate: delete from smbms_user where id=?
Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.createdBy as createdb4_0_0_, user0_.creationDate as creation5_0_0_, user0_.gender as gender6_0_0_, user0_.modifyBy as modifyby7_0_0_, user0_.modifyDate as modifyda8_0_0_, user0_.phone as phone9_0_0_, user0_.userCode as usercod10_0_0_, user0_.userName as usernam11_0_0_, user0_.userPassword as userpas12_0_0_, user0_.userRole as userrol13_0_0_ from smbms_user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.createdBy as createdb4_0_0_, user0_.creationDate as creation5_0_0_, user0_.gender as gender6_0_0_, user0_.modifyBy as modifyby7_0_0_, user0_.modifyDate as modifyda8_0_0_, user0_.phone as phone9_0_0_, user0_.userCode as usercod10_0_0_, user0_.userName as usernam11_0_0_, user0_.userPassword as userpas12_0_0_, user0_.userRole as userrol13_0_0_ from smbms_user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_0_0_, user0_.address as address2_0_0_, user0_.birthday as birthday3_0_0_, user0_.createdBy as createdb4_0_0_, user0_.creationDate as creation5_0_0_, user0_.gender as gender6_0_0_, user0_.modifyBy as modifyby7_0_0_, user0_.modifyDate as modifyda8_0_0_, user0_.phone as phone9_0_0_, user0_.userCode as usercod10_0_0_, user0_.userName as usernam11_0_0_, user0_.userPassword as userpas12_0_0_, user0_.userRole as userrol13_0_0_ from smbms_user user0_ where user0_.id=?
Hibernate: delete from smbms_user where id=? or id=? or id=?

SpringData JPA的查询

第一种查询方式:约定方法名

  • Spring Data JPA会根据前缀、中间连接词(Or、And、Like、NotNull等类似SQL中的关键词),内部拼接SQL代理生成方法的实现。
  • 约定方法名一定要符合命名规范
关键词SQL符号样例对应JPQL 语句片段
AndandfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrorfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,Equals=findByFirstname,findByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
Betweenbetween xxx and xxxfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThan<findByAgeLessThan… where x.age < ?1
LessThanEqual<=findByAgeLessThanEqual… where x.age <= ?1
GreaterThan>findByAgeGreaterThan… where x.age > ?1
GreaterThanEqual>=findByAgeGreaterThanEqual… where x.age >= ?1
After>findByStartDateAfter… where x.startDate > ?1
Before<findByStartDateBefore… where x.startDate < ?1
IsNullis nullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullis not nullfindByAge(Is)NotNull… where x.age not null
LikelikefindByFirstnameLike… where x.firstname like ?1
NotLikenot likefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithlike ‘xxx%’findByFirstnameStartingWith… where x.firstname like ?1(parameter bound with appended %)
EndingWithlike ‘xxx%’findByFirstnameEndingWith… where x.firstname like ?1(parameter bound with prepended %)
Containinglike ‘%xxx%’findByFirstnameContaining… where x.firstname like ?1(parameter bound wrapped in %)
OrderByorder byfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
Not<>findByLastnameNot… where x.lastname <> ?1
Inin()findByAgeIn(Collection ages)… where x.age in ?1
NotInnot in()findByAgeNotIn(Collection ages)… where x.age not in ?1
TRUE=truefindByActiveTrue()… where x.active = true
FALSE=falsefindByActiveFalse()… where x.active = false
IgnoreCaseupper(xxx)=upper(yyyy)findByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

示例

dao层

java">public interface UserRepository extends JpaRepository<User, Integer> {User findByUserCode(String userCode);
}

service层

java">    public Object findByUserCode(String userCode){return userRepository.findByUserCode(userCode);}

测试

java">    @Testvoid findByUserCode() {userService.findByUserCode("admin");}

执行结果如下:

java">Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.birthday as birthday3_0_, user0_.createdBy as createdb4_0_, user0_.creationDate as creation5_0_, user0_.gender as gender6_0_, user0_.modifyBy as modifyby7_0_, user0_.modifyDate as modifyda8_0_, user0_.phone as phone9_0_, user0_.userCode as usercod10_0_, user0_.userName as usernam11_0_, user0_.userPassword as userpas12_0_, user0_.userRole as userrol13_0_ from smbms_user user0_ where user0_.userCode=?

第二种查询方式:使用JPQL查询

  • JPQL的全称为Java Persistence Query Language,是一种和SQL非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的SQL语言,从而屏蔽不同数据库之间的差异。
  • JPQL和SQL很像,查询关键字都是一样的,唯一的区别是JPQL是面向对象的。
  • JPQL里面不能出现表名,列名,只能出现Java的类名,属性名,并且区分大小写。不能使用select *。
  • JPQL通过@Query注解,封装了执行数据库的查询的相关方法

示例

dao层

java">    @Query(value = "select u.userName from User u where u.userCode=?1")//@Query(value = "select u from User u where u.userCode=?1")String selByCode(String userCode);

service层

java">    public Object findByUserCode(String userCode){//return userRepository.findByUserCode(userCode);return userRepository.selByCode(userCode);}

测试执行结果如下:

java">Hibernate: select user0_.userName as col_0_0_ from smbms_user user0_ where user0_.userCode=?

第三种查询方式:使用Exampler查询

  • 在 JpaRepository<T, ID>接口中定义了如下的方法
    • List findAll(Example var1);
    • List findAll(Example var1, Sort var2);
  • Example接口,代表的是完整的查询条件。由实体对象(查询条件值)和匹配器(查询方式)共同创建。最终根据实例来findAll即可。
  • 匹配器:ExampleMatcher对象,它是匹配“实体对象”的,表示了如何使用“实体对象”中的“值”进行查询,它代表的是“查询方式”,解释了如何去查的问题。
  • 如:要查询姓“王”的客户,即姓名以“王”开头的客户,该对象就表示了“以某某开头的”这个查询方式。

示例

service层

java">    public List<User> getUser() {User user = new User();//user.setUserCode("zhanghua");user.setUserRole(3);user.setCreatedBy(2);Example<User> example = Example.of(user);return userRepository.findAll(example);}

测试

java">    @Testvoid getUser() {List<User> userList = userService.getUser();userList.forEach(System.out::println);}

执行结果如下:

java">Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.birthday as birthday3_0_, user0_.createdBy as createdb4_0_, user0_.creationDate as creation5_0_, user0_.gender as gender6_0_, user0_.modifyBy as modifyby7_0_, user0_.modifyDate as modifyda8_0_, user0_.phone as phone9_0_, user0_.userCode as usercod10_0_, user0_.userName as usernam11_0_, user0_.userPassword as userpas12_0_, user0_.userRole as userrol13_0_ from smbms_user user0_ where user0_.userRole=3 and user0_.createdBy=2
User(id=8, userCode=zhaoyan, userName=赵燕, userPassword=1, gender=1, birthday=1986-03-07 00:00:00.0, phone=18098764545, address=北京市海淀区回龙观小区10号楼, userRole=3, createdBy=2, creationDate=2016-04-21 13:54:07.0, modifyBy=null, modifyDate=null)
User(id=10, userCode=sunlei, userName=孙磊, userPassword=1, gender=2, birthday=1981-01-04 00:00:00.0, phone=13387676765, address=北京市朝阳区管庄新月小区12, userRole=3, createdBy=2, creationDate=2015-05-06 10:52:07.0, modifyBy=null, modifyDate=null)

第四种查询方式:使用原生SQL查询

  • JPQL通过@Query注解,封装了执行数据库的查询的相关方法在

示例

dao层

java">    @Query(value = "select * from smbms_user where phone = :phone",nativeQuery = true)List<User> getUserByPhone(@Param("phone") String phone);

service层

java">    public  List<User> findUserByPhone() {return userRepository.getUserByPhone("13387676765");}

测试执行结果如下:

java">Hibernate: select * from smbms_user where phone = ?
User(id=10, userCode=sunlei, userName=孙磊, userPassword=1, gender=2, birthday=1981-01-04 00:00:00.0, phone=13387676765, address=北京市朝阳区管庄新月小区12, userRole=3, createdBy=2, creationDate=2015-05-06 10:52:07.0, modifyBy=null, modifyDate=null)

分页查询:

方式1:PagingAndSortingRepository分页接口,适用于简单的分页查询;

示例1

service层

java">    public Page<User> page(Integer currentPage) {User user = new User();//user.setUserCode("zhanghua");user.setUserRole(3);user.setCreatedBy(1);ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreCase().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);Example<User> example = Example.of(user,matcher);Pageable pageable = PageRequest.of(currentPage-1,5, Sort.by(Sort.Order.desc("birthday")));return userRepository.findAll(example,pageable);}

测试

java">    @Testvoid page() {Page<User> pageResult = userService.page(1);System.out.println(pageResult);}

执行结果如下:

java">Hibernate: select user0_.id as id1_0_, user0_.address as address2_0_, user0_.birthday as birthday3_0_, user0_.createdBy as createdb4_0_, user0_.creationDate as creation5_0_, user0_.gender as gender6_0_, user0_.modifyBy as modifyby7_0_, user0_.modifyDate as modifyda8_0_, user0_.phone as phone9_0_, user0_.userCode as usercod10_0_, user0_.userName as usernam11_0_, user0_.userPassword as userpas12_0_, user0_.userRole as userrol13_0_ from smbms_user user0_ where user0_.createdBy=1 and user0_.userRole=3 order by user0_.birthday desc limit ?
Page 1 of 1 containing cn.smbms.pojo.User instances
示例2:

dao层

java">    Page<User> findByUserCode(String userCode, Pageable pageable);

service层

java">    public Page<User> page(Integer currentPage) {Pageable pageable = PageRequest.of(currentPage-1,5, Sort.by(Sort.Order.desc("birthday")));return userRepository.findByUserCode("admin",pageable);}

方式2:Specification。自定义方法findAll,适用于动态分页查询;

  • Specification 是Spring Data JPA提供的一种用于构建动态查询条件的接口,可以根据不同的条件动态组合查询条件,自定义的UserRepository 必须实现JpaSpecificationExecutor接口
示例

dao层

java">Page<SysUser> findAll(Specification<SysUser> specification,Pageable pageable);

service层

java">@Overridepublic Page<SysUser> findUserList(String userName, Integer userRole, Integer currentPageNo, Integer pageSize) throws Exception {Specification<SysUser> specification=new Specification<SysUser>() {@Overridepublic Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {//断言List<Predicate> predicateList=new ArrayList<>();if(!StringUtils.isEmpty(userName)){Predicate predicate=criteriaBuilder.like(root.get("userName").as(String.class),"%"+userName+"%");predicateList.add(predicate);}if(!StringUtils.isEmpty(userRole) && userRole>0){Predicate predicate=criteriaBuilder.equal(root.get("userRole").as(Integer.class),userRole);predicateList.add(predicate);}return criteriaBuilder.and(predicateList.toArray(new Predicate[0]));}};Sort sort=Sort.by(Sort.Order.desc("id"));Pageable pageable=PageRequest.of(currentPageNo-1,pageSize,sort);return userRepository.findAll(specification,pageable);}

SpringData JPA配置多数据源

同源数据库的多源支持

日常项目中因为使用的分布式开发模式,不同的服务有不同的数据源,常常需要在一个项目中使用多个数据源,因此需要配置 Spring Boot Jpa 对多数据源的使用,一般分一下为三步:

  1. 配置多数据源
  2. 不同源的实体类放入不同包路径
  3. 声明不同的包路径下使用不同的数据源、事务支持

异构数据库多源支持

比如我们的项目中,即需要对 mysql 的支持,也需要对 Mongodb 的查询等。实体类声明@Entity 关系型数据库支持类型,声明@Document 为 Mongodb 支持类型,不同的数据源使用不同的实体就可以了。

示例

java">interface PersonRepository extends Repository<Person, Long> {}@Entity
public class Person {}interface UserRepository extends Repository<User, Long> {}@Document
public class User {}

如果 User 用户既使用 Mysql 也使用 Mongodb也可以做混合使用

java">interface JpaPersonRepository extends Repository<Person, Long> {}interface MongoDBPersonRepository extends Repository<Person, Long> {}@Entity
@Document
public class Person {}

也可以通过对不同的包路径进行声明,比如 A 包路径下使用 mysql,B 包路径下使用 MongoDB。

java">@EnableJpaRepositories(basePackages = "com.neo.repositories.jpa")
@EnableMongoRepositories(basePackages = "com.neo.repositories.mongo")
interface Configuration { }

多数据源使用案例

1.依赖

2.配置

spring:datasource:smbms:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&username: rootpassword: 123456news:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/news?useUnicode=true&characterEncoding=utf-8&useSSL=false&username: rootpassword: 123456jpa:show-sql: trueproperties:hibernate:hbm2ddl:auto: updatedialect: org.hibernate.dialect.MySQL5InnoDBDialectformat_sql: true

3.实体类

4.配置类

java">package cn.smbms.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Map;/*** @author: zjl* @datetime: 2024/4/24* @desc:*/
@Configuration
public class DataSourceConfig {@Resourceprivate JpaProperties jpaProperties;@Resourceprivate HibernateProperties hibernateProperties;@Bean(name = "smbmsDataSource")@Primary@ConfigurationProperties("spring.datasource.smbms")public DataSource firstDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "secondaryDataSource")@ConfigurationProperties("spring.datasource.secondary")public DataSource secondDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "vendorProperties")public Map<String, Object> getVendorProperties() {return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(),new HibernateSettings());}
}
java">package cn.smbms.config;import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;/*** @author: zjl* @datetime: 2024/4/24* @desc:*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryPrimary",transactionManagerRef = "transactionManagerPrimary",basePackages = {"cn.smbms.dao"})//设置dao(repo)所在位置
public class SmbmsConfig {@Resource(name = "smbmsDataSource")private DataSource dataSource;@Resource(name = "vendorProperties")private Map<String, Object> vendorProperties;@Bean(name = "entityManagerFactoryPrimary")@Primarypublic LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {return builder.dataSource(dataSource).properties(vendorProperties).packages("cn.smbms.pojo") //设置实体类所在位置.persistenceUnit("primaryPersistenceUnit").build();}@Bean(name = "entityManagerPrimary")@Primarypublic EntityManager entityManager(EntityManagerFactoryBuilder builder) {return entityManagerFactoryPrimary(builder).getObject().createEntityManager();}@Bean(name = "transactionManagerPrimary")@PrimaryPlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());}}
java">package cn.smbms.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;/*** @author: zjl* @datetime: 2024/4/24* @desc:*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactorySecondary",transactionManagerRef = "transactionManagerSecondary",basePackages = {"cn.smbms.news.dao"})
public class NewsConfig {@Autowired@Qualifier("newsDataSource")private DataSource dataSource;@Autowired@Qualifier("vendorProperties")private Map<String, Object> vendorProperties;@Bean(name = "entityManagerFactorySecondary")public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {return builder.dataSource(dataSource).properties(vendorProperties).packages("com.example.springbootmultijpa.model").persistenceUnit("secondaryPersistenceUnit").build();}@Bean(name = "entityManagerSecondary")public EntityManager entityManager(EntityManagerFactoryBuilder builder) {return entityManagerFactorySecondary(builder).getObject().createEntityManager();}@Bean(name = "transactionManagerSecondary")PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());}
}

5.业务逻辑层

6.测试


http://www.ppmy.cn/news/1440779.html

相关文章

vite-electron 静默打印功能实现

系列文章目录 electronvitevue3 快速入门教程 文章目录 系列文章目录前言一、实现方案二、< webview />讲解1、属性2、 监听事件3、方法 三、 webview与渲染进程通信1.渲染进程--->webview2.webview--->渲染进程&#xff1a; 四、代码实战打印样式说明踩坑说明 前…

如何在Windows 11中安装或删除可选功能?这里提供详细步骤

序言 Windows 11提供了各种各样的功能,其中许多功能,如Linux的Windows子系统(WSL)和语言包,它默认情况下不会安装。你也可以删除默认情况下安装的功能,以下是如何以图形方式或从命令行执行此操作。 关于Windows 11中的可选功能,你需要了解的内容 还有其他添加和删除功…

第一章Hadoop概述

1. Hadoop是什么 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。广义上来说&#xff0c;Hadoop通常是指一个更广泛的概念--Hadoop生态圈 2. Hadoop发展历史&#xff08;了解&#xff09; Hadoop创始人…

debian配置distcc分布式编译

前言 distcc 是一个用于在网络上的多台机器上分发 C、C、Objective C 或 Objective C 代码构建的程序。 distcc 应始终生成与本地构建相同的结果&#xff0c;易于安装和使用&#xff0c;并且通常比本地编译快得多。 distcc 不要求所有机器共享文件系统、同步时钟或安装相同的…

Autosar MCAL-RH850P1HC Fls配置

文章目录 FlsFlsGeneralFlsAcLoadOnJobStartFlsBaseAddressFlsBlankCheckApiFlsCancelApiFlsCompareApiFlsCopySupportedFlsCriticalSectionProtectionFlsDevErrorDetectFlsDeviceNameFlsDriverIndexFlsFaciEccCheckFlsGetJobResultApiFlsGetStatusApiFlsLoopCountFlsReadImmed…

用flutter实现类似startActivityForResult和onActivityResult功能

今年实在是大卷元年呀&#xff0c;莫名其妙的flutter就开始在各大公司火了起来&#xff0c;然后就是全员学习flutter&#xff0c;公司可以不用&#xff0c;但是你必须得会。隔壁IOS同事瑟瑟发抖&#xff0c;咋啦&#xff1f;意思就是我走咯&#xff1f; 不管怎么说&#xff0c;…

AI预测体彩排列3第2套算法实战化测试第5弹2024年4月27日第5次测试

今天继续进行新算法的测试&#xff0c;今天是第5次测试。好了&#xff0c;废话不多说了&#xff0c;直接上图上结果。 2024年4月27日体彩排3预测结果 6码定位方案如下&#xff1a; 百位&#xff1a;6、2、1、7、8、9 十位&#xff1a;8、9、4、3、1、0 个位&#xff1a;3、7、8…

Nest 快速上手 —— (一)nest介绍与启动安装

参考资料&#xff1a;https://docs.nestjs.com/ 0.介绍 Nest (NestJS)是一个用于构建高效、可扩展的Node.js服务器端应用程序的框架。它使用渐进式JavaScript&#xff0c;构建并完全支持TypeScript(但仍然允许开发人员使用纯JavaScript编写代码)&#xff0c;并结合了OOP(面向对…