Spring JPA 查询创建

这是JPA内容的核心部分,可以收藏用作参阅文档。

1. 查询转化和关键字

例:一个JPA查询的转化

public interface UserRepository extends Repository<User, Long> {

  List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}

我们使用JPA 标准API创建一个查询,但从本质上讲,这将转换为以下查询:select u from User u where u.emailAddress = ?1 and u.lastname = ?2,Spring Data JPA执行属性检查并遍历嵌套属性,如属性表达式中所述。

下表描述了JPA支持的关键字,以及包含该关键字的方法可以转换成什么查询语句:

表:查询关键字及对应查询语句

关键字 样例 JPQL片段(转化的查询语句)
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … 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
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (参数绑定附加 %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (参数绑定附加 %)
Containing findByFirstnameContaining … where x.firstname like ?1 (参数绑定附加 %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

InNotIn也接受集合的任何子类以及数组作为一个参数或可变参数。对于相同逻辑运算符的其他语法版本,请检查存储库查询关键字。

2. 使用@Query 自定义查询

​ 使用自命名查询声明实体的查询是一种有效的方法,该方法适用于少量查询。由于查询本身绑定到执行它们的Java方法上,实际上可以通过使用Spring Data JPA @Query注释直接绑定,而不用将它们注释到域类。这将域类从特定于持久性的信息中解放出来,并将查询合并到该存储库接口:

​ 注释@Query查询优先于使用@NamedQuery定义的查询和在orm.xml中声明的自命名查询。

例:使用@Query在查询方法上声明查询

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}

3. 使用高级LIKE表达式

​ 使用@Query创建的自命名查询的查询执行机制允许在查询定义中定义高级LIKE表达式,如下面的示例所示:

例:@Query中定义的LIKE表达式

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname like %?1")
List<User> findByFirstnameEndsWith(String firstname);
}

​ 在前面的示例中,识别了LIKE的分隔符字符(%),并将查询转换为有效的JPQL查询(移除%)。在执行查询时,传递给方法调用的参数将使用之前识别的LIKE模式进行扩充。

4. 使用原生查询

​ 将nativeQuery标志设置为true, @Query注释允许运行原生查询,如下面的示例所示:

例:使用@Query在查询方法上声明一个原生查询

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}

Spring Data JPA目前不支持原生查询的动态排序,因为它必须操作声明的实际查询,而这对本地SQL来说是不可靠的。但是,您可以通过自己指定count查询来对本机查询的结果进行分页,如下面的示例所示:

例:通过使用@Query在查询方法上声明用于分页的本机计数查询

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
}

5.使用Sort

​ 我们可以通过PageRequestSort直接完成排序,SortOrder实例中实际使用的属性需要与您的域模型(持久化模型)匹配。这意味着它们需要解析为查询中使用的属性或别名。JPQL将其定义为状态字段路径表达式。

使用任何不可引用的路径表达式都会导致异常。

​ 但是,使用Sort@Query可以让您插入包含Order BY子句在内的函数非路径检查的Order实例,您可以使用JpaSort。添加可能不安全的排序。

例:使用SortJpaSort

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.lastname like ?1%")
List<User> findByAndSort(String lastname, Sort sort); @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
} repo.findByAndSort("lannister", new Sort("firstname")); //在域模型中指向属性的有效排序表达式
repo.findByAndSort("stark", new Sort("LENGTH(firstname)")); //包含函数调用的无效排序。Thows 异常
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); //包含显式不安全顺序的有效排序。
repo.findByAsArrayAndSort("bolton", new Sort("fn_len")); //指向别名函数的有效排序表达式。

6.使用(自)命名参数

​ 默认情况下,Spring Data JPA使用基于位置的参数绑定,如上面的所有示例所述,即参数和?的位置一一顺序对应。这使得查询方法在重构参数位置时容易出错。要解决这个问题,可以使用@Param注释为方法参数提供一个具体名称,并在查询中绑定该名称,如下面的示例所示:

例:使用命名参数

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
}

这样子就不需要再保证位置的一一对应了,只需要保证名称的对应即可,方法参数根据它们在定义的查询中的顺序进行切换

参考文档

1.翻译:【JPA Query Methods】

Spring JPA 查询创建的更多相关文章

  1. spring data jpa 查询自定义字段,转换为自定义实体

    目标:查询数据库中的字段,然后转换成 JSON 格式的数据,返回前台. 环境:idea 2016.3.4, jdk 1.8, mysql 5.6, spring-boot 1.5.2 背景:首先建立 ...

  2. Spring JPA 定义查询方法

    Spring JPA 定义查询方法 翻译:Defining Query Methods ​ 存储库代理有两种方式基于方法名派生特定域的查询方式: 直接从方法名派生查询 自定义查询方式 ​ 可用选项基于 ...

  3. Spring JPA使用CriteriaBuilder动态构造查询

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://www.cnblogs.com/mzdljgz/p/11495723. ...

  4. spring jpa 自定义查询数据库的某个字段

    spring jpa 提供的查询很强大, 就看你会不会用了. 先上代码, 后面在解释吧 1. 想查单个表的某个字段 在repository中 @Query(value = "select i ...

  5. spring data jpa查询部分字段、多余附加字段

    spring data jpa查询部分字段 第一种方法:使用 model 查询时转化 首先建立一个 model ,写上自己想要查询的字段,然后写上构造函数,这步很重要,因为spring jpa 转化时 ...

  6. Spring JPA学习笔记

    目录 什么是JPA? 引入配置 新建一个Entity Bean类 JPA的增删改查 新建操作接口 新建测试类 总结 什么是JPA? 什么是JDBC知道吧?数据库有Mysql,SQL Server,Or ...

  7. 使用Spring JPA中Page、Pageable接口和Sort类完成分页排序

    显示时,有三个参数,前两个必填,第几页,一页多少个size,第三个参数默认可以不填. 但是发现这个方法已经过时了,通过查看它的源码发现,新方法为静态方法PageRequest of(page,size ...

  8. spring jpa和mybatis整合

    spring jpa和mybatis整合 前一阵子接手了一个使用SpringBoot 和spring-data-jpa开发的项目 后期新加入一个小伙伴,表示jpa相比mybatis太难用,多表联合的查 ...

  9. spring.jpa.open-view问题

    由ReentrantLock和JPA(spring.jpa.open-in-view)导致的死锁问题原因分析. 问题 在压测过程中,发现服务经过一段时间压测之后出现无响应,且无法自动恢复. 分析 从上 ...

随机推荐

  1. java_线程、同步、线程池

    线程 Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例 Thread类常用方法 构造方法 public Thread():分配一个新的线程 ...

  2. [leetcode/lintcode 题解] Google面试题:合法组合

    给一个单词s,和一个字符串集合str.这个单词每次去掉一个字母,直到剩下最后一个字母.求验证是否存在一种删除的顺序,这个顺序下所有的单词都在str中.例如单词是’abc’,字符串集合是{‘a’,’ab ...

  3. Flutter 容器(8) - SizedOverflowBox | OverflowBox

    SizedOverflowBox: 子组件在超出SizedOverflowBox指定的宽高时,不会隐藏,依然进行绘制 OverflowBox: 限制子组件的宽高. import 'package:fl ...

  4. 解Bug之路-dubbo流量上线时的非平滑问题

    前言 笔者最近解决了一个困扰了业务系统很久的问题.这个问题只在发布时出现,每次只影响一两次调用,相较于其它的问题来说,这个问题有点不够受重视.由于种种原因,使得这个问题到了业务必须解决的程度,于是就到 ...

  5. 微信支付.NET SDK 中的BUG(存疑)

    BUG出现在类文件WxPayData.cs中的FromXml(string xml)方法 /** * @将xml转为WxPayData对象并返回对象内部的数据 * @param string 待转换的 ...

  6. Uni-app从入门到实战

    前言 uni-app是一个使用vue.js开发跨平台应用的前端框架,开发者只需要编写一套代码,便可以发布到IOS.Android和微信小程序等多个平台.所以我打算学习下这个框架,快速浏览了一遍官网之后 ...

  7. vue调起微信JSDK 扫一扫,相册等需要注意的事项

    在VUE里面需要注意的第一个问题就是路由得设置成 2:第二个就是 跳转路由的时候 不要用this.$router.push 或者this.$router.replace  前者在ios 和安卓端都调不 ...

  8. 实战分享丨MySQL 与Django版本匹配相关经验

    摘要:关于MySQL 与Django版本匹配相关知识的经验分享. run: (env) E:\PythonPro\PyDjangoProDemo011\xuanyuaniotpro>python ...

  9. Java进阶专题(十一) 探究JMM

    前言 ​ JMM即java内存模型,JMM研究的就是多线程下Java代码的执行顺序,共享变量的读写.它定义了Java虚拟机在计算机内存中的工作方式.从抽象角度看,JMM定义了线程和主存之间的抽象关系: ...

  10. 2.Oracle数据库安装教程

    一.准备安装 基本都是按部就班. 使用的OS版本:OEL4 安装程序路径: /mnt/Oracle11g_linux_x86_64/database 创建用户 使用的.bash_profile 修改的 ...