【Spring Boot】JPA 的查询方式

JPA 的查询方式

  • 1.使用约定方法名
  • 2.用 JPQL 进行查询
  • 3.用原生 SQL 进行查询
    • 3.1 根据 ID 查询用户
    • 3.2 查询所有用户
    • 3.3 根据 email 查询用户
    • 3.4 根据 name 查询用户,并返回分页对象 Page
    • 3.5 根据名字来修改 email 的值
    • 3.6 使用事务
  • 4.用 Specifications 进行查询
  • 5.用 ExampleMatcher 进行查询
  • 6.用谓语 QueryDSL 进行查询
  • 7.用 NamedQuery 进行查询

1.使用约定方法名

约定方法名一定要根据命名规范来写,Spring Data 会根据前缀、中间连接词(OrAndLikeNotNull 等类似 SQL 中的关键词)、内部拼接 SQL 代理生成方法的实现。

约定方法名的方法见下表(不完全示例):

SQL
方法例子
JPQL 语句
andfindByLastnameAndFirstnamewhere x.lastname = ?1 and x.firstname = ?2
orfindByLastnameOrFirstnamewhere x.lastname = ?1 or x.firstname = ?2
=findByFirstname / findByFirstnameIs / findByFirstnameEqualswhere x.firstname = ?1

接口方法的命名规则也很简单,只要明白 AndOrIsEqualGreaterStartingWith 等英文单词的含义,就可以写接口方法。具体用法如下:

public interface UserRepository extends Repository<User, Long> {List<User> findByEmailOrName(String email, String name);
}

上述代码表示,通过 emailname 来查找 User 对象。

约定方法名还可以支持以下几种语法:

  • User findFirstByOrderByNameAsc()
  • Page<User> queryFirst100ByName(String name, Pageable pageable)
  • Slice<User> findTop100ByName(String name, Pageable pageable)
  • List<User> findFirst100ByName(String name, Sort sort)
  • List<User> findTop100ByName(String name, Pageable pageable)

2.用 JPQL 进行查询

JPQL 语言(Java Persistence Query Language)是一种和 SQL 非常类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 语言,从而屏蔽不同数据库的差异。

JPQL 语言通过 Query 接口封装执行,Query 接口封装了执行数据库查询的相关方法。调用 EntityManager 的 Query、NamedQuery 及 NativeQuery 方法可以获得查询对象,进而可调用 Query 接口的相关方法来执行查询操作。

JPQL 是面向对象进行查询的语言,可以通过自定义的 JPQL 完成 UPDATE 和 DELETE 操作。JPQL 不支持使用 INSERT。对于 UPDATE 或 DELETE 操作,必须使用注解 @Modifying 进行修饰。

JPQL 的用法见以下两段代码。

(1)下面代码表示根据 name 值进行查找。

public interface UserRepository extends JpaRepository<User, Long> (@Query("select u from User u where u.name = ?1")User findByName(String name);
}

(2)下面代码表示根据 name 值进行模糊查找。

public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.name like %?1")List<User> findByName(String name);
}

3.用原生 SQL 进行查询

在使用原生 SQL 查询时,也使用注解 @Query。此时,nativeQuery 参数需要设置为 true。 下面先看一些简单的查询代码。

3.1 根据 ID 查询用户

public interface UserRepository extends JpaRepository<User, Long> (// 根据 ID 查询用户@Query(value = "select * from user u where u.id=:id", nativeQuery = true)User findById(@Param("id")Long id);
)

3.2 查询所有用户

public interface UserRepository extends JpaRepository<User, Long> {// 查询所有用户@Query(value = "select * from user", nativeQuery = true)List<User> findAllNative();
}

3.3 根据 email 查询用户

public interface UserRepository extends JpaRepository<User, Long> (// 根据 email 查询用户@Query(value = "select * from user where email= ?1", nativeQuery = true) User findByEmail(String email);
)

3.4 根据 name 查询用户,并返回分页对象 Page

public interface UserRepository extends JpaRepository<User, Long> (@Query(value = "select * from user where name= ?1",countQuery = "select count(*) from user where name= ?1", nativeQuery = true)Page<User> findByName(String name, Pageable pageable);
}

3.5 根据名字来修改 email 的值

@Modifying 
@Query("update user set email = :email where name =:name")
Void updateUserEmailByName(@Param("name")String name, @Param("email")String email);

3.6 使用事务

UPDATE 或 DELETE 操作需要使用事务。此时需要先定义 Service 层,然后在 Service 层的方法上添加事务操作。

对于自定义的方法,如果需要改变 Spring Data 提供的事务默认方式,则可以在方法上使用注解 @Transactional,如以下代码:

@Service
public classUserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void updateEmailByName(String name, String email) {userRepository.updateUserEmaiByName(name, email);}
)

测试代码:

@Test
public void testUsingModifingAnnotation() {userService.updateEmailByName("pipi", "88888888@qq.com");
}

在进行多个 Repository 操作时,也应该使这些操作在同一个事务中。按照分层架构的思想,这些操作属于业务逻辑层,因此需要在 Service 层实现对多个 Repository 的调用,并在相应的方法上声明事务。

4.用 Specifications 进行查询

如果要使 Repository 支持 Specification 查询,则需要在 Repository 中继承 JpaSpecificationExecutor 接口,具体使用见如下代码:

public interface CardRepository extends JpaRepository<Card,Long>, JpaSpecificationExecutor<Card> {Card findById(long id);
}

下面以一个例子来说明 Specifications 的具体用法:

@SpringBootTest
@RunWith(SpringRunner.class)
public class testJpaSpecificationExecutor (@Autowiredprivate CardRepository cardRepository;@Testpublic void testJpaSpecificationExecutor() (int pageNo = 0;int pageSize = 5;PageRequest pageable = PageRequest.of(pageNo, pageSize);// 通常使用 Specification 的匿名内部类Specification<Card> specification = new Specification<Card>() {@Overridepublic Predicate toPredicate(Root<Card> root, CriteriaQuery<?> query, CriteriaBuilder cb) {Path path = root.get("id");// gt 是大于的意思。这里代表 id 大于 2Predicate predicate1 = cb.gt(path, 2);// equal 是等于的意思,代表查询 num 值为 422803 的数据记录Predicate predicate2 = cb.equal(root.get("num"), 422803);// 构建组合的 PredicatePredicate predicate = cb.and(predicate1, predicate2); return predicate;}};Page<Card> page = cardRepository.findAll(specification, pageable);System.out.println("总记录数: " + page.getTotalElements());System.out.println("当前第: " + (page.getNumber() + 1) + "页");System.out.println("总页数: " + page.getTotalPages());System.out.println("当前页面的 List: " + page.getContent());System.out.println("当前页面的记录数: "+ page.getNumberOfElements());}
)

代码解释如下:

  • CriteriaQuery 接口:specific 的顶层查询对象,它包含查询的各个部分,比如,selectfromwheregroup byorder by 等。CriteriaQuery 对象只对实体类型或嵌入式类型的 Criteria 查询起作用。
  • root:代表查询的实体类是 Criteria 查询的根对象。Criteria 查询的根定义了实体类型,能为将来的导航获得想要的结果。它与 SQL 查询中的 From 子句类似。Root 实例是类型化的, 且规定了 From 子句中能够出现的类型。查询根实例通过传入一个实体类型给 AbstractQuery.from 方法获得。
  • query:可以从中得到 Root 对象,即告知 JPA Criteria 查询要查询哪一个实体类。还可以添加查询条件,并结合 EntityManager 对象得到最终查询的 TypedQuery 对象。
  • CriteriaBuilder 对象:用于创建 Criteria 相关对象的工厂,可以从中获取到 Predicate 对象。
  • Predicate 类型:代表一个查询条件。

运行上面的测试代码,在控制台会输出如下结果(确保数据库已经存在数据):

Hibernate: select card0_.id as id1_0_, card0_.num as num2_0_ from card cardO_ where card0_.id>2 and card0_.num=422803 limit ?
Hibernate: select count(card0_.id) as col_0_0_ from card card0_ where card0_.id>2 and card0_.num=422803
总记录数: 6
当前第: 1页 
总页数: 2 
当前页面的 List: [Card(id=4, num=422803), Card(id=8, num=422803), Card(id=10, num=422803), Card(id=20, num=422803), Card(id=23, num=422803)] 
当前页面的记录数: 5

5.用 ExampleMatcher 进行查询

Spring Data 可以通过 Example 对象来构造 JPQL 查询,具体用法见以下代码:

User user = new User();
//构建查询条件
user.setName("pipi")ExampleMatcher matcher = ExampleMatcher.matching()// 创建一个 ExampleMatcher, 不区分大小写匹配 name.withIgnorePaths("name")// 包括 null 值.withIncludeNullValues()// 执行后缀匹配.withStringMatcherEnding();
// 通过 Example 构建查询
Example<User> example = Example.of(user, matcher);
List<User> list = userRepository.findALL(example);

默认情况下,ExampleMatcher 会匹配所有字段。

可以指定单个属性的行为(如 name 或内嵌属性 name.user)。如:

  • withMatcher("name", endsWith())
  • withMatcher("name", startsWith().ignoreCase())

6.用谓语 QueryDSL 进行查询

QueryDSL 也是基于各种 ORM 之上的一个通用查询框架,它与 Spring Data JPA 是同级别的。使用 QueryDSL 的 API 可以写出 SQL 语句(Java 代码,非真正标准 SQL),不需要懂 SQL 语句。它能够构建类型安全的查询。这与 JPA 使用原生查询时有很大的不同,可以不必再对 Object[] 进行操作。它还可以和 JPA 联合使用。

7.用 NamedQuery 进行查询

官方不推荐使用 NamedQuery,因为它的代码必须写在实体类上面,这样不够独立。其使用方法见以下代码:

©Entity 
@NamedQuery(name = "User.findByName", query = "select u from User u where u.name = ?1") 
public class User {
}

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

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

相关文章

Mac视频下载工具,兼容14系统,Downie 4软件下载

Downie 4 是一款由James Application开发的视频下载软件&#xff0c;支持Mac操作系统。该软件允许用户从各种视频网站上下载视频内容&#xff0c;以便于在本地设备上观看&#xff0c;无需依赖互联网连接。自动下载&#xff1a;可以设置Downie 4自动下载指定网站上的视频&#x…

当+=的时候,为什么会出现NaN?

问: var textToDisplay; // "testing"; textToDisplay "testing"; textToDisplay 1; var someNumber 1; var oneMoreNumber; oneMoreNumber textToDisplay someNumber; //results in NaN console.log(oneMoreNumber); 这里的结果是NaN? 回答: 是…

【LinuxC语言】线程池的原理和实现

文章目录 前言为什么需要线程池线程池的原理总结前言 在现代计算中,多线程编程已经成为一种常见的做法,它可以帮助我们更有效地利用多核处理器的能力。然而,频繁地创建和销毁线程会带来一定的开销。为了解决这个问题,我们可以使用一种称为“线程池”的技术。线程池是一种在…

黑马点评-Redis的缓存击穿,缓存雪崩,缓存穿透,互斥锁,逻辑过期

文章目录 1.缓存穿透2.缓存雪崩3.缓存击穿3.1 互斥锁3.2 基于逻辑过期 1.缓存穿透 解决办法 写入NULL值到Redis缓存&#xff0c;以后就会命中Redis的控制缓存而不会出现请求直接打到数据库的问题&#xff01; 代码 2.缓存雪崩 这个概念很好理解&#xff0c;雪崩就是无数的…

【LLM大模型书】从零开始大模型开发与微调:基于PyTorch与ChatGLM (附PDF)

今天又来给大家推荐一本大模型方面的书籍<从零开始大模型开发与微调&#xff1a;基于PyTorch与ChatGLM>。 本书使用PyTorch 2.0作为学习大模型的基本框架&#xff0c;以ChatGLM为例详细讲解大模型的基本理论、算法、程序实现、应用实战以及微调技术&#xff0c;为读者揭…

设备树在Linux系统的属性

设备树源文件 设备树源文件扩展名为.dts&#xff0c;我们在前面移植 Linux 的时候却一直在使用.dtb 文件&#xff0c;那么 DTS 和 DTB 这两个文件是什么关系呢&#xff1f; DTS 是设备树源码文件&#xff0c; DTB 是将 DTS 编译以后得到的二进制文件。将.dts 编译为.dtb 需要什…

【微信小程序开发实战项目】——如何制作一个属于自己的花店微信小程序(2)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

FreeRTOS和UCOS操作系统使用笔记

FreeRTOS使用示例 UCOS使用示例 信号量使用 信号量访问共享资源区/ OS_SEMMY_SEM; //定义一个信号量&#xff0c;用于访问共享资源OSSemCreate ((OS_SEM* )&MY_SEM, //创建信号量&#xff0c;指向信号量(CPU_CHAR* )"MY_SEM", //信号量名字(OS_SEM_CTR )1, …

软件模型分类及特点

在软件开发的世界里&#xff0c;我们经常会遇到业务模型、系统模型和软件模型这三个层次。这些模型各有特点&#xff0c;相互之间也有着紧密的联系。通过理解这三个层次之间的映射关系&#xff0c;我们能更好地理解和掌握软件开发的全过程 1. 业务模型 业务模型描述了组织的业…

政务单位网站SSL证书选择策略

在数字化快速发展的今天&#xff0c;政务单位网站作为政府与公众沟通的重要桥梁&#xff0c;其安全性和可信度显得尤为重要。SSL证书作为保障网站安全的重要手段&#xff0c;其选择对于政务单位网站来说至关重要。本文将探讨政务单位网站在选择SSL证书时应该考虑的因素&#xf…

如何使用python网络爬虫批量获取公共资源数据教程?

原文链接&#xff1a;如何使用python网络爬虫批量获取公共资源数据教程&#xff1f;https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608240&idx4&snef281f66727afabfaae2066c6e92f792&chksmfa826657cdf5ef41571115328a09b9d34367d8b11415d5a5781dc4c…

【AI提升】如何使用大模型:本机离线和FastAPI服务调用

大模型本身提供的功能&#xff0c;类似于windows中的一个exe小工具&#xff0c;我们可以本机离线调用然后完成具体的功能&#xff0c;但是别的机器需要访问这个exe是不可行的。常见的做法就是用web容器封装起来&#xff0c;提供一个http接口&#xff0c;然后接口在后端调用这个…

KV260视觉AI套件--PYNQ-DPU-Resnet50

目录 1. 简介 2. 代码解析 3. 全部代码展示 4. 总结 1. 简介 本文以 Resnet50 为例&#xff0c;展示使用 PYNQ 调用 DPU 运行 Resnet50 网络的详细过程&#xff0c;并对其中关键代码做出解释。 PYNQ是一个针对Xilinx Zynq平台的Python开发框架&#xff0c;它允许开发者使…

KEYSIGHT是德科技 E5063A ENA 系列网络分析仪

E5063A ENA 矢量网络分析仪 18GHz 2端口 降低无源射频元器件的测试成本 Keysight E5063A ENA 是一款经济适用的台式矢量网络分析仪&#xff0c;可用于测试简单的无源元器件&#xff0c;例如频率最高达到 18 GHz 的天线、滤波器、电缆或连接器。 作为业界闻名的 ENA 系列…

深入解析 Laravel 事件系统:架构、实现与应用

Laravel 的事件系统是框架中一个强大且灵活的功能&#xff0c;它允许开发者在应用程序中定义和使用自定义事件和监听器。这个系统基于观察者模式&#xff0c;使得代码解耦和可维护性大大提高。在本文中&#xff0c;我们将深入探讨 Laravel 事件系统的工作原理、如何实现自定义事…

python @装饰器的用法

装饰器&#xff08;decorators&#xff09;是 Python 中的一种高级特性&#xff0c;它允许开发者修改函数或方法的行为&#xff0c;而不改变其定义。装饰器通常用于日志记录、权限检查、性能测量等场景。装饰器是通过在函数定义的前一行加上 decorator_name 来使用的。 基本用…

Qt简单文本查找

Qt版本&#xff1a; Qt6 具体代码&#xff1a; 1. 头文件 mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>class QLineEdit; class QDialog; class QPushButton; class QVBoxLayout; class QTextEdit;QT_BEGIN_NAMESPACE namespace Ui…

为什么AI算法工程师要求C++?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c&#xff0b;&#xff0b;的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;能跑出…

找到字符串中所有子串出现的位置python

直接find干就完了。 如果你希望找到字符串中所有子串出现的位置&#xff0c;而不仅仅是一个位置&#xff0c;你可以通过循环查找并收集所有起始位置。以下是修改后的代码&#xff1a; def find_all_substring_positions(string, substring): positions [] # 用于存储所有…

与枚举结合的策略模式

枚举类&#xff1a; package com.dtranx.tools.corpora.businessapi.enums;import com.dtranx.tools.commons.vo.EnumResponseVo; import com.google.common.collect.Lists;import java.util.List;/*** ClassName SimpleSearchMode* Description TODO* Date 2024/5/28 15:55* A…