语法及其源码
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# */ 必须有;
- 估计有可能随着版本的变化这个会做优化。
- 另外一种实现方法就是自己写两个查询方法,自己手动分页。