Spring Data JPA 从入门到精通~@Query详解

37 篇文章 10 订阅

语法及其源码

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 用法

使用命名查询为实体声明查询是一种有效的方法,对于少量查询很有效。一般只需要关心 @Query 里面的 value 和 nativeQuery 的值。使用声明式 JPQL 查询有个好处,就是启动的时候就知道你的语法正确不正确。

注意:好的架构师写代码时报错的顺序是编译<启动<运行时,即越早发现错误越好。默认 value 里面是 JPQL 语法,既对象查询和 SQL、HQL 比较类似。

案例 4.1:声明一个注解在 Repository 的查询方法上。

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

案例 4.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);
}

案例 4.3:直接用原始 SQL。

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
  User findByEmailAddress(String emailAddress);
}

注意:nativeQuery 不支持直接 Sort 的参数查询。

案例4.4:nativeQuery 的排序错误的写法,下面这个是启动不起来的。

public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "select * from user_info where first_name=?1",nativeQuery = true)
List<UserInfoEntity> findByFirstName(String firstName,Sort sort);
}

案例4.5:nativeQuery 排序的写法。

@Query(value = "select * from user_info where first_name=?1 order by ?2",nativeQuery = true)
List<UserInfoEntity> findByFirstName(String firstName,String sort);
//调用的地方写法last_name是数据里面的字段名,不是对象的字段名
repository.findByFirstName("jackzhang","last_name");

@Query 的排序

@Query 的 JPQL 情况下,想实现排序,方法上面直接用 PageRequest 或者直接用 Sort 参数都可以做到。

在排序实例中实际使用的属性需要与实体模型里面的字段相匹配,这意味着它们需要解析为查询中使用的属性或别名。这是一个state_field_path_expression JPQL定义,并且 Sort 的对象支持一些特定的函数。

案例 4.6: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")); 

@Query 的分页

案例 4.7:直接用 Page 对象接受接口,参数直接用 Pageable 的实现类即可。

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

案例 4.8:对原生 SQL 的分页支持,案例如下,但是支持的不是特别友好,以 MySQL 为例。

 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 ?, ?

注意:

  • 这个注释 /* #pageable# */ 必须有;
  • 估计有可能随着版本的变化这个会做优化。
  • 另外一种实现方法就是自己写两个查询方法,自己手动分页。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值