Spring Data JPA 基本用法笔记整理

写在前面:

之前一直写MyBatis,去年开始做的这个新项目用的是JPA,整理了一些基本使用方法

1、 集成方法:

1.1 引入依赖

<!--spring data 依赖-->
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-jpa</artifactId></dependency>
<!--数据库连接-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

1.2 配置文件

配置数据库信息:

//数据库连接信息
spring.datasource.url= url
spring.datasource.username=username
spring.datasource.password=<password>//Java代码实体字段命名与数据库表结构字段之间的名称映射策略
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
//下面配置开启后,会禁止将驼峰转为下划线
//spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
//是否打印运行时的sql
spring.jpa.show-sql=false//控制是否可以基于程序中Entity的定义自动创建或者修改DB中表结构 
//create -> 重启后删除上一次的表,重新生成
//create-drop -> sessionFactory关闭时,创建的表就自动删除,服务启动后重新创建
//validate -> 验证创建数据库表结构,不同就报错
//update none
//等价于spring.jpa.hibernate.ddl-auto
spring.jpa.properties.hibernate.hbm2ddl.auto=update

1.3 入口注解

没有特殊需求可以什么都不加

@SpringBootApplication
@EntityScan("path") //指定实体的目录
@EnbaleJpaRepositories(basePackages = {"com.veezean.demo.repository"}) //指定扫描的表repository目录
@EnableJpaAuditing//开启JPA auditing能力,可以自动赋值一些字段,比如创建时间、最后一次修改时间etc
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

 

2、基本用法

2.1 实体映射类 Entity

实体类编写比较简单,只需要在普通的Java数据类上添加一些注解,用来描述字段的一些附加信息

@Data
@Entity
@Table(name = "user")
@EntityListeners(value = AuditingEntityListener.class)//对实体属性变化的跟踪
public class UserEntity {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String workId;private String userName;@ManyToOne(optional = false)@JoinColumn(name = "department")private DepartmentEntity department;@CreatedDateprivate Date createTime;@LastModifiedDateprivate Date updateTime;}

2.2 常用注解

 

 

2.3 Repository

2.3.1 三种 Repository

Spring Data 扩展了Repository接口,提供了一些便于操作数据库的子类,对主体repository层级提供的主要方法进行简单的梳理:

  • CrudRepository: 提供基本的CRUD操作。
  • PagingAndSortingRepository: 在父类的基础上提供分页、排序的能力
  • JpaRepository: 在父类的基础上,提供了查询列表、批量删除、强制同步以及Example查询等能力

3.3.2 自定义Repository类

 

 

自定义Repository时,继承JpaRepository需要传入两个泛型:

1、需要操作的具体Entity对象;

2、Entity的主键数据类型

@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {List<UserEntity> findAllByDepartment(DepartmentEntity department);UserEntity findFirstByWorkId(String workId);List<UserEntity> findAllByDepartmentInAndUserNameLike(List<DepartmentEntity> departmentIds, String userName);
}

3.4 查询

如上所述,简单的操作只需要基于SpringData JPA的命名规范进行接口方法的命名即可,无需关注具体实现,也不需要提供实现类

但是面对复杂的操作,这样的定义方式就不再适用了,那么应该如何做呢?

不固定查询字段的场景(Example)

例:需要做一个用户搜索的能力,要求支持根据用户名、工号、部门、性别、年龄、职务等等若干个字段中的1个或者多个的组合来查询符合条件的用户信息。

🌟 使用 Example查询

public Page<UserEntity> queryUsers(Request request, UserEntity queryParams) {// 查询条件构造出对应Entity对象,转为Example查询条件Example<UserEntity> example = Example.of(queryParams);// 构造分页参数Pageable pageable = PageHelper.buildPageable(request);// 按照条件查询,并分页返回结果return userRepository.findAll(example, pageable);
}

🔸查询条件复杂时为了不使方法名称过长也可以使用 Example

public List<User> findUsersByNameAndAge(String name, Integer age) {  User user = new User();  user.setName(name);  user.setAge(age);  ExampleMatcher matcher = ExampleMatcher.matching()  .withMatcher("name", match -> match.contains())  .withMatcher("age", match -> match.exact());  Example<User> example = Example.of(user, matcher);  return userRepository.findByExample(example);  }  

❗example只能针对字符串进行条件设置

复杂场景(SQL, Specification)

🌟定制SQL

遇到非常复杂的查询场景也可以通过定制SQL的方式实现

@Query(value = "select t.*,(select group_concat(a.assigner_name) from workflow_task a where a.state='R' and a.proc_inst_id=t.proc_inst_id) deal_person,"+ " (select a.task_name from workflow_task a where a.state='R' and a.proc_inst_id=t.proc_inst_id limit 1) cur_step "+ "   from workflow_info t where t.state='R'  and t.type in (?1) "+ "and exists(select 1 from workflow_task b where b.assigner=?2 and b.state='R' and b.proc_inst_id=t.proc_inst_id) order by t.create_time desc",countQuery = "select count(1) from workflow_info t where t.state='R'  and t.type in (?1) "+ "and exists(select 1 from workflow_task b where b.assigner=?2 and b.state='R' and b.proc_inst_id=t.proc_inst_id) ",nativeQuery = true)Page<FlowResource> queryResource(List<String> type, String workId, Pageable pageable);

🌟Specification 构建动态查询

1️⃣ 需要定义一个Specification,用来构建查询条件:

Specification<User> spec = (root, query, criteriaBuilder) -> {Path<Integer> type = root.get("verified");// verified == "1"Predicate verifiedPredicate = criteriaBuilder.equal(type, "1");// email like "%qq%"Path<String> email = root.get("email");Predicate emailPredicate = criteriaBuilder.like(email, "%qq%");// and 条件 verified == "1" and email like "%qq%"Predicate predicate = criteriaBuilder.and(verifiedPredicate, emailPredicate);return predicate;};

lambda表达式中传入的3个参数分别为:

Root:查询哪个表(关联查询) = from CriteriaQuery:查询哪些字段,排序是什么 =组合(order by . where ) CriteriaBuilder:条件之间是什么关系,如何生成一个查询条件,每一个查询条件都是什么类型(> between in...) = where

Specification接口中只定义了如下一个方法:

//构造查询条件/***	root	:Root接口,代表查询的根对象,可以通过root获取实体中的属性*	query	:代表一个顶层查询对象,用来自定义查询*	cb		:用来构建查询,此对象里有很多条件方法* Predicate(Expression): 每一条查询条件的详细描述**/
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);

因此也可以通过匿名内部类的方式:

Specification <User> spec = new Specification<User>() {public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {//cb:构建查询,添加查询方式   like:模糊匹配//root:从实体Customer对象中按照custName属性进行查询return cb.like(root.get("name").as(String.class), "111%");}};

2️⃣ 自定义一个repository接口,继承JpaRepository和JpaSpecificationExecutor

@Repository  
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {  
}

JpaSpecificationExecutor 接口中定义了如下方法:

 public interface JpaSpecificationExecutor<T> {//根据条件查询一个对象T findOne(Specification<T> spec);	//根据条件查询集合List<T> findAll(Specification<T> spec);//根据条件分页查询Page<T> findAll(Specification<T> spec, Pageable pageable);//排序查询查询List<T> findAll(Specification<T> spec, Sort sort);//统计查询long count(Specification<T> spec);
}

3️⃣ 使用时只需调用repository中的findAll方法,并传入相应参数即可:

userRepository.findAll(specification);  

3.5 分页、排序

Pageable

分页,排序使用Pageable对象进行传递,其中包含Page和Sort参数对象。查询时直接传递

List<User> findAllByDepartment(Department dept, Pageable pageable);

** Specification 查询分页也只需要构造Pageable参数并传入

Slice结果对象

**还有一种特殊的分页场景。比如,DB表中有100w条记录,然后现在需要将这些数据全量的加载到ES中。如果逐条查询然后插入ES,显然效率太慢;如果一次性全部查询出来然后直接往ES写,服务端内存可能会爆掉。

🌟 这种场景可以基于Slice结果对象实现

Slice的作用是,只知道是否有下一个Slice可用,不会执行count

private <T extends EsDocument, F> void fullLoadToEs(IESLoadService<T, F> esLoadService) {try {final int batchHandleSize = 10000;Pageable pageable = PageRequest.of(0, batchHandleSize);do {// 批量加载数据,返回Slice类型结果Slice<F> entitySilce = esLoadService.slicePageQueryData(pageable);// 具体业务处理逻辑List<T> esDocumentData = esLoadService.buildEsDocumentData(entitySilce);esUtil.batchSaveOrUpdateAsync(esDocumentData);// 获取本次实际上加载到的具体数据量int pageLoadedCount = entitySilce.getNumberOfElements();if (!entitySilce.hasNext()) {break;}// 自动重置page分页参数,继续拉取下一批数据pageable = entitySilce.nextPageable();} while (true);} catch (Exception e) {log.error("error occurred when load data into es", e);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17236.html

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

相关文章

leetcode-495.提莫攻击

leetcode-495.提莫攻击 文章目录 leetcode-495.提莫攻击一.题目描述二.代码提交三.解释 一.题目描述 二.代码提交 #include <vector> using namespace std;int findPoisonedDuration(vector<int>& timeSeries, int duration) {int total 0;for (int i 0; i …

团队没有测试人员,要快速完成测试?

有同学提问:产品没有专职的测试人员,要怎么才能快速完成测试? 先说结论,这个问题并没有标准答案 没有测试岗位只是没有专门负责这个职能的人员,但测试这个事并没有消失 快速完成测试,其实应该换种说法,就是快速建立质量信心。 因为测试无穷尽,所以没有绝对的完成测试…

光学相位---描述周期性波动现象

相位是描述周期性波动现象的一个重要物理量&#xff0c;用来表示波在某一时刻或位置上的振荡状态。它是时间、空间和频率的函数&#xff0c;通常用角度&#xff08;单位为度或弧度&#xff09;来表示。对于光波而言&#xff0c;其相位可以通过波的传播距离、波长以及波数来定义…

一、通义灵码插件保姆级教学-IDEA(安装篇)

JetBrains IDEA 中安装教学 第一步&#xff1a;事先准备 支持系统&#xff1a;Windows 7 ~ Windows 11、Linux、macOS&#xff1b;下载并安装兼容的 JetBrains IDEA 2020.3 及以上版本&#xff1b; 第二步&#xff1a;在 IntelliJ IDEA 中安装通义灵码 方法 1&#xff1a;通…

系统之间数据对接怎么做

系统之间数据对接怎么做&#xff1a;数据同步功能详解 在当今数字化时代&#xff0c;企业往往依赖于多个系统来管理不同的业务流程。这些系统可能包括客户关系管理&#xff08;CRM&#xff09;、企业资源规划&#xff08;ERP&#xff09;、供应链管理&#xff08;SCM&#xff…

Java NIO ByteBuffer 详解

什么是 ByteBuffer ByteBuffer 是 Buffer 的一个具体实现&#xff0c;专门用于存储和操作字节数据。它提供了高效的、基于内存的 I/O 数据处理方式。 Buffer 类是构建 Java NIO 的基础&#xff0c;其中 ByteBuffer 类是 Buffer 子类中最受欢迎的。这是因为字节类型是最通用的…

OnlyOffice编辑器下载失败排查与解决方案

OnlyOffice编辑器下载失败排查与解决方案 问题描述原因分析&#xff1a;1. 检查后端服务地址是否正确2. 使用内部IP地址访问后端服务 其他常见问题 在使用OnlyOffice编辑器时&#xff0c;常见的问题之一是无法正确显示图片或打开文档。 具体表现为提示图片URL地址不正确或打开…

栈的实现-

栈 栈的概念及结构 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除的一端称为栈顶&#xff0c;另一端称为栈底。栈中元素遵循**后进先出 LIFO&#xff08;Last In First Out&#xff09;**的原则。 压栈&#xff1a;栈的…

在vivado中对数据进行延时,时序对齐问题上的理清

在verilog的ISP处理流程中&#xff0c;在完成第一个模块的过程中&#xff0c;我经常感到困惑&#xff0c;到底是延时了多少个时钟&#xff1f;今日对这几个进行分类理解。 目录 1.输入信号激励源描述 1.1将数据延时[9]个clk 1.2将vtdc与hzdc延时[9]个clk(等价于单bit的数据…

singleTaskAndroid的Activity启动模式知识点总结

一. 前提知识 1.1. 任务栈知识 二. Activity启动模式的学习 2.1 standard 2.2 singleTop 2.3.singleTask 2.4.singleInstance 引言&#xff1a; Activity作为四大组件之一&#xff0c;也可以说Activity是其中最重要的一个组件&#xff0c;其负责调节APP的视图&#xff…

Tetragon:一款基于eBPF的运行时环境安全监控工具

关于Tetragon Tetragon是一款基于eBPF的运行时环境安全监控工具&#xff0c;该工具可以帮助广大研究人员检测并应对安全重大事件&#xff0c;例如流程执行事件、系统调用活动、I/O活动&#xff08;包括网络和文件访问等&#xff09;。 在 Kubernetes 环境中使用时&#xff0c;…

提升编程效率,体验智能编程助手—豆包MarsCode一键Apply功能测评

提升编程效率&#xff0c;体验智能编程助手—豆包MarsCode一键Apply功能测评 &#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 引言豆包…

卷积定理理解:如何将系数多项式乘法降到n*log n的复杂度?

目标 两个向量&#xff08;每个向量各自对应一个多项式&#xff09;的简单相乘&#xff08;时间复杂度 O ( n 2 ) O(n^2) O(n2)&#xff09;可以通过两个向量各自对应的离散傅里叶变换的相乘&#xff08;时间复杂度 O ( n ⋅ lg n ) O(n\cdot \text{lg }n) O(n⋅lg n)&#xf…

【devops】 Git仓库如何fork一个私有仓库到自己的私有仓库 | git fork 私有仓库

一、场景说明 场景&#xff1a; 比如我们Codeup的私有仓库下载代码 放入我们的Github私有仓库 且保持2个仓库是可以实现fork的状态&#xff0c;即&#xff1a;Github会可以更新到Codeup的最新代码 二、解决方案 1、先从Codeup下载私有仓库代码 下载代码使用 git clone 命令…

解析 JavaScript 面试题:`index | 0` 确保数组索引为整数

文章目录 一、JavaScript 中的数字类型二、按位或运算符 | 的作用&#xff08;一&#xff09;对于整数&#xff08;二&#xff09;对于小数&#xff08;三&#xff09;对于非数字值 三、用于数组索引的意义 在 JavaScript 面试中&#xff0c;常常会涉及到一些看似简单却蕴含着深…

考研操作系统----操作系统的概念定义功能和目标(仅仅作为王道哔站课程讲义作用)

目录 操作系统的概念定义功能和目标 操作系统的四个特征 操作系统的分类 ​编辑 操作系统的运行机制 系统调用 操作系统体系结构 操作系统引导 虚拟机 操作系统的概念定义功能和目标 什么是操作系统&#xff1a; 操作系统是指控制和管理整个计算机系统的软硬件资源&…

基于SpringBoot+ Vue实现在线视频点播系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

【Java常用】注解与反射_2.反射

目录标题 1.Java反射机制概述1.静态 VS 动态语言1.1动态语言举例展示JavaScript作为动态语言的特性1. 运行时代码生成和执行2.动态变量创建3.对比静态语言&#xff08;如 Java&#xff09;&#xff1a; 1.2 静态语言 2.理解Class类并获取Class实例3.类的加载与ClassLoader4.创建…

MySQL主从同步+binlog

一、简介 MySQL内建的复制功能是构建大型&#xff0c;高性能应用程序的基础 通过将MySQL的某一台主机&#xff08;master&#xff09;的数据复制到其他主机&#xff08;slaves&#xff09;上&#xff0c;并重新执行一遍来执行 复制过程中一台服务器充当主服务器&#xff0c;而…

PCB多层板打样:深度解析优缺点与应用场景

随着电子产品朝小型化、高性能化方向发展&#xff0c;PCB多层板扮演着越来越重要的角色。无论是智能手机、计算机&#xff0c;还是航空航天、工业控制&#xff0c;多层板都发挥着至关重要的作用。像专业的PCB制造商——嘉立创&#xff0c;凭借超高层工艺&#xff0c;可以生产最…