【SpringBoot整合系列】SpringBoot整合JPA

目录

  • 前期回顾
    • 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.实体类

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为主键的数据类型

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

5.添加用户业务实现类

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

6.测试

测试添加

  • 因为设置了主键ID的策略为自增,因此不用传ID就会执行添加操作。
  • 也可以传一个不存在的ID,也会执行新增操作,但是主键并不是自定义的主键值,而是自增的主键值
@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);}
}
  • 执行结果如下:
    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,会触发修改,若属性为空,会将对应的字段值也修改为空,因此需要特别注意
    @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
  • 执行结果如下:
    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层

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

测试

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

执行结果如下:

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层

    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);}

测试

    @Testvoid delete() {userService.delete();}

执行结果如下:

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层

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

service层

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

测试

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

执行结果如下:

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层

    @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层

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

测试执行结果如下:

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层

    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);}

测试

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

执行结果如下:

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层

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

service层

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

测试执行结果如下:

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层

    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);}

测试

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

执行结果如下:

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层

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

service层

    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层

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

service层

@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 支持类型,不同的数据源使用不同的实体就可以了。

示例

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

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

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

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

@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.配置类

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());}
}
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());}}
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.mzph.cn/pingmian/3022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

element-ui upload 组件 手动多次出发 submit

element 上传组件 upload 上传成功以后&#xff0c;想重新 调用 submit()函数&#xff0c;发现是不可以进行多次触发的,。 直接上解决方法&#xff0c;在上传成功后的钩子函数里添加:fileList[0l.status ready fileList是文件列表&#xff0c;status是单文件的状态改成ready就…

【Fastadmin】表格导出excel,图片显示太大

目录 1.直接导出示例 2.解决办法 3. 再次导出效果 1.直接导出示例 图片过大&#xff0c;格式错乱 2.解决办法 在js页面加入代码 // 导出图片过大处理 exportOptions: {ignoreColumn: [0, operate],onBeforeSaveToFile: function (data, fileName, type, charset, encoding,…

《深入Linux设备驱动程序内核机制》学习笔记-第4章

前言 本文是《深入Linux设备驱动程序内核机制》的读书笔记&#xff0c;本文因为是读书笔记所以抄写引用了该书中的大量内容&#xff0c;写读书笔记的目的是在写作的过程中加深对书中内容的理解。 建议读者直接阅读《深入Linux设备驱动程序内核机制》&#xff0c;这本书是Linu…

mPEG-Dansyl,Methoxy PEG Dansyl由甲氧基-聚乙二醇(mPEG)和丹磺酰氯(Dansyl)两部分组成

【试剂详情】 英文名称 mPEG-Dansyl&#xff0c;Methoxy PEG Dansyl 中文名称 聚乙二醇单甲醚丹磺酸酯&#xff0c;甲氧基-聚乙二醇-丹磺酰胺 外观性状 由分子量决定&#xff0c;液体或者固体 分子量 0.4k&#xff0c;0.6k&#xff0c;1k&#xff0c;2k&#xff0c;3.4k…

前端发送请求,显示超时取消

前端发送请求&#xff0c;显示超时取消 问题说明&#xff1a;后台接口请求60s尚未完成&#xff0c;前端控制台显示取消&#xff08;canceled&#xff09; 原因 1、前端设置60s超时则取消 2、后台接口响应时间过长&#xff0c;过长的原因统计的数据量多&#xff08;实际也才17…

LLM 安全 | 大语言模型应用安全入门

一、背景 2023年以来&#xff0c;LLM 变成了相当炙手可热的话题&#xff0c;以 ChatGPT 为代表的 LLM 的出现&#xff0c;让人们看到了无限的可能性。ChatGPT能写作&#xff0c;能翻译&#xff0c;能创作诗歌和故事&#xff0c;甚至能一定程度上做一些高度专业化的工作&#x…

BUUCTF-Misc20

[ACTF新生赛2020]NTFS数据流1 1.打开附件 是一堆文件&#xff0c;随便打开一个内容是flag不在这 2.pyton脚本 编写查找文件夹下一堆文件中那个文件藏有flag的Python脚本 import os def search_flag_files(folder_path, flag): flag_files [] for root, dirs, files …

HAL STM32 SSI/SPI方式读取MT6701磁编码器获取角度例程

HAL STM32 SSI/SPI方式读取MT6701磁编码器获取角度例程 &#x1f4cd;相关篇《HAL STM32 I2C方式读取MT6701磁编码器获取角度例程》&#x1f4cc;当前最新MT6701数据手册&#xff1a;https://www.magntek.com.cn/upload/MT6701_Rev.1.8.pdf&#x1f4dc;SSI协议读角度&#xff…

【stomp实战】搭建一套websocket推送平台

前面几个小节我们已经学习了stomp协议&#xff0c;了解了stomp客户端的用法&#xff0c;并且搭建了一个小的后台demo&#xff0c;前端页面通过html页面与后端服务建立WebSocket连接。发送消息给后端服务。后端服务将消息内容原样送回。通过这个demo我们学习了前端stomp客户端的…

剑指 Offer 03.:数组中重复的数字

剑指 Offer 03. 数组中重复的数字 找出数组中重复的数字。 在一个长度为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数字重复了&#xff0c;也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。…

DIN特征加权、POSO特征增强、SENET特征选择

本文转自&#xff1a;DIN、POSO、SENet 聊聊推荐模型中常用的Attention-腾讯云开发者社区-腾讯云 一、前言 聊起模型结构的时候&#xff0c;经常听做推荐的同学说&#xff1a; "这里加了个self-attention" "类似于一个SENet" "一个魔改的POSO"…

[Visual Studio 报错] error 找不到指定的 SDK“Microsoft

[Visual Studio 2022 报错] error : 找不到指定的 SDK“Microsoft.NET.Sdk.Web” 问题描述&#xff1a; 在新电脑上安装了VS2022&#xff0c;打开现有项目的解决方案后的时候报了这个错&#xff0c;所有projet文件都加载失败,如图所示&#xff1a; 报错分析及解决 打开项目配…

经验丰富也被裁了,失业快2年找不到工作?

前几天徐工说&#xff0c;他有个邻居&#xff0c;最近逮到他总是要跟他扯上几句。 原因是徐工一直是做嵌入式开发&#xff0c;而他一直做纯软件开发&#xff0c;具体不知道做后端还是前端。 他说&#xff0c;他至少有半年没上班了&#xff0c;之前在一家龙头物流公司上班。 碰上…

STM32 HAL库F103系列之DAC实验(二)

DAC输出正弦波实验 实验简要 1&#xff0c;功能描述 通过DAC1通道1(PA4)输出正弦波&#xff0c;然后通过DS100示波器查看波形 2&#xff0c;使用定时器7 TRGO事件触发转换 TEN1位置1、TSEL1[2:0]010 3&#xff0c;关闭输出缓冲 BOFF1位置1 4&#xff0c;使用DMA模式 DMAE…

SLMs之Phi-3:Phi-3的简介、安装和使用方法、案例应用之详细攻略

SLMs之Phi-3&#xff1a;Phi-3的简介、安装和使用方法、案例应用之详细攻略 导读&#xff1a;2024年4月23日&#xff0c;微软发布Phi-3&#xff0c;这是微软推出的一款新的开源AI模型家族Phi-3。背景痛点&#xff1a;小语言模型(SLM)尽管规模不大&#xff0c;但在语言理解、代码…

盲盒商城小程序(有米就出)

一款前端采用uniapp&#xff0c;后端采用Django框架开发的小程序&#xff0c;包含后台管理&#xff0c;如有人需要可联系演示功能&#xff08;个人开发&#xff0c;可商用/学习&#xff09;。 部分截图如下&#xff1a;

文件摆渡:安全、高效的摆渡系统助力提升效率

很多组织和企业都会通过网络隔离的方式来保护内部的数据&#xff0c;网络隔离可以是物理隔离&#xff0c;也可以是逻辑隔离&#xff0c;如使用防火墙、VPN、DMZ等技术手段来实现&#xff0c;隔离之后还会去寻找文件摆渡方式&#xff0c;来保障日常的业务和经营需求。 进行网络隔…

数据库变更时,OceanBase如何自动生成回滚 SQL

背景 在开发中&#xff0c;数据的变更与维护工作一般较频繁。当我们执行数据库的DML操作时&#xff0c;必须谨慎考虑变更对数据可能产生的后果&#xff0c;以及变更是否能够顺利执行。若出现意外数据丢失、操作失误或语法错误等情况&#xff0c;我们必须迅速将数据库恢复到变更…

jsp+springboot+java二手车交易管理系统258u6

设计而成的系统要有以下目标&#xff1a;管理员和用户能够跳转到不同的页面当中。因此要把系统的目标设置为如下几项&#xff1a; (1) 系统在操作上不能过于复杂。 (2) 用户对应着不同的角色 (3) 设计完成的数据库要有能够处理并发和安全的作用 (4) 设计完成的管理…

亚马逊云科技提高企业生产力神器Amazon Q评测分析

一年一度的全球云计算春晚&#xff0c;亚马逊云科技Re:invent在2023年11月27于Vegas震撼来袭&#xff0c;其中最令人关注的就是CEO Adam在Keynote中分享的内容。其中一个新内容就是提升生产力神器: Amazon Q&#xff0c;可以说它重新定义了企业的工作模式。那具体它神在哪里呢&…