@Query注解
快速体验 @Query 的方法:
入门案例:
public interface UserDtoRepository extends JpaRepository<User,Long> {
//通过query注解根据name查询user信息
@Query("From User where name=:name")
User findByQuery(@Param("name") String nameParam);
}
public void testQueryAnnotation() {
//新增一条数据方便测试 userDtoRepository.save(User.builder().name("jackxx").email("123456@126.com").sex("man").address("shanghai").build());
//调用上面的方法查看结果
User user2 = userDtoRepository.findByQuery("jack");
System.out.println(user2);
}
最后可以在控制台看到结果,说明@Query 注解在其中起了作用,使 "From User where name=:name"JPQL 生效了。
@Query 的基本用法
在之前学过的查询策略设置中,有一个QueryLookupStrategy.Key 的值,其中的CREATE_IF_NOT_FOUND:这个是默认的,先用声明方式(@Query)进行查找,如果没有找到与方法相匹配的查询。在QueryExecutorMethodInterceptor 类中,可以看到默认的策略是CreateIfNotFound,也就是如果有@Query注解,那么以@Query的注解内容为准,可以忽略方法名。
先看一下它的注解源码,了解一下基本用法。
package org.springframework.data.jpa.repository;
public @interface Query {
/**
* 指定JPQL的查询语句。(nativeQuery=true的时候,是原生的Sql语句)
*/
String value() default "";
/**
* 指定count的JPQL语句,如果不指定将根据query自动生成。
* (如果当nativeQuery=true的时候,指的是原生的Sql语句)
*/
String countQuery() default "";
/**
* 根据哪个字段来count,一般默认即可。
*/
String countProjection() default "";
/**
* 默认是false,表示value里面是不是原生的sql语句
*/
boolean nativeQuery() default false;
/**
* 可以指定一个query的名字,必须唯一的。
* 如果不指定,默认的生成规则是:
* {$domainClass}.${queryMethodName}
*/
String name() default "";
/*
* 可以指定一个count的query的名字,必须唯一的。
* 如果不指定,默认的生成规则是:
* {$domainClass}.${queryMethodName}.count
*/
String countName() default "";
}
@Query 用法是使用 JPQL 为实体创建声明式查询方法。我们一般只需要关心 @Query 里面的 value 和 nativeQuery、countQuery 的值即可。
JPQL 的语法
先看一下查询的语法结构,代码如下:
SELECT … FROM …
[WHERE …]
[GROUP BY … [HAVING …]]
[ORDER BY …]
它的语法结构有点类似我们 SQL,唯一的区别就是 JPQL FROM 后面跟的是对象,而 SQL 里面的字段对应的是对象里面的属性字段。
update 和 delete 的语法结构:
DELETE FROM … [WHERE …]
UPDATE … SET … [WHERE …]
其中“…”省略的部分是实体对象名字和实体对象里面的字段名字,而其中类似 SQL 一样包含的语法关键字有:SELECT FROM WHERE UPDATE DELETE JOIN OUTER INNER LEFT GROUP BY HAVING FETCH DISTINCT OBJECT NULL TRUE FALSE NOT AND OR BETWEEN LIKE IN AS UNKNOWN EMPTY MEMBER OF IS AVG MAX MIN SUM COUNT ORDER BY ASC DESC MOD UPPER LOWER TRIM POSITION CHARACTER_LENGTH CHAR_LENGTH BIT_LENGTH CURRENT_TIME CURRENT_DATE CURRENT_TIMESTAMP NEW EXISTS ALL ANY SOME 等。。。
参考学习文档:https://docs.oracle.com/html/E13946_04/ejb3_langref.html
@Query 用法案例
下面通过几个案例来了解一下 @Query 的用法,你就可以知道 @Query 怎么使用、怎么传递参数、怎么分页等。
案例1:
要在 Repository 的查询方法上声明一个注解,这里就是 @Query 注解标注的地方。
public interface UserRepository extends JpaRepository<User, Long>{
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
案例 2:
LIKE 查询,注意 firstname 不会自动加上“%”关键字。
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.firstname like %?1")
List<User> findByFirstnameEndsWith(String firstname);
}
案例3:
直接用原始 SQL,nativeQuery = true 即可。
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
需要注意:
nativeQuery 不支持直接 Sort 的参数查询。
@Query中在用JPQL的时候,想要实现排序,方法上直接用 PageRequest 或者 Sort 参数都可以做到。
在排序实例中,实际使用的属性需要与实体模型里面的字段相匹配,这意味着它们需要解析为查询中使用的属性或别名。
案例 4:
Sort and JpaSort 的使用,它可以进行排序。
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)"));
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)"));
repo.findByAsArrayAndSort("bolton", new Sort("fn_len"));
案例5:
@Query 的分页分为两种情况,分别为 JQPl 的排序和 nativeQuery 的排序。
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "select u from User u where u.lastname = ?1")
Page<User> findByLastname(String lastname, Pageable pageable);
}
//调用者的写法
repository.findByFirstName("jackzhang",new PageRequest(1,10));
案例 6:
@Query 对原生 SQL 的分页支持,并不是特别友好,因为这种写法比较“骇客”,可能随着版本的不同会有所变化。
public interface UserRepository extends JpaRepository<UserInfoEntity, Integer>, JpaSpecificationExecutor<UserInfoEntity> {
@Query(value = "select * from user_info where first_name=?1 /* #pageable# */",
countQuery = "select count(*) from user_info where first_name=?1",
nativeQuery = true)
Page<UserInfoEntity> findByFirstName(String firstName, Pageable pageable);
}
//调用者的写法
return userRepository.findByFirstName("jackzhang",new PageRequest(1,10, Sort.Direction.DESC,"last_name"));
//打印出来的sql
select * from user_info where first_name=? /* #pageable# */ order by last_name desc limit ?, ?
案例7:
@Param 注解指定方法参数的具体名称,通过绑定的参数名字指定查询条件,这样不需要关心参数的顺序。我比较推荐这种做法,因为它比较利于代码重构。如果不用 @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);
}
案例 8:
根据参数进行查询,top 10 前面说的“query method”关键字照样有用
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findTop10ByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
}
本文详细介绍了如何在Spring Data JPA中使用@Query注解进行JPQL查询,包括基础用法、语法示例、分页排序、参数传递和命名查询。通过实例演示了如何创建动态查询、LIKE查询和原生SQL,以及如何优雅地处理排序和分页操作。
1193

被折叠的 条评论
为什么被折叠?



