定义查询方法
从方法名称中可以制定特定用于存储的查询和更新
通过使用@Query注解手动定义查询
方法的查询策略设置
通过 @EnableJpaRepositories(queryLookupStrategy = QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND) 的 queryLookupStrategy参数设置
QueryLookupStrategy.Key的值有三个:
- CREATE: 直接根据方法名进行创建,规则是根据方法名称的构造进行尝试,如果方法名不符合规则,启动的时候就会报异常
- USE_DECLARED_QUERY:声明式创建,启动的时候尝试找到一个声明的查询,如果没有找到就抛出一个异常
- CREATE_IF_NOT_FOUND: 默认值,以上两种方法的结合版
编写查询方法
待查询功能的方法名由查询策略(关键字)、查询字段和一些限制性条件组成
关键字列表(待补充)
查询结果处理
参数选择分页和排序
1.特定类型的参数,动态地将分页和排序应用于查询
// 当用到 Page 的时候会默认执行一条 count Page<SystemUser> findByUname(String uname, Pageable pageable); // 只知道是否有下一个 Slice 可用,不会执行count,不关心一共有多少页 Slice<SystemUser> findByUname(String uname,Pageable pageable); // 排序支持返回List,排序也可以通过 Pageable 实例处理 List<SystemUser> findByUname(String uname, Sort sort); // 分页支持返回List,page将不会创建构建实例所需的实例元数据 List<SystemUser> findByUname(String uname, Pageable pageable);
2.限制查询结果
SystemUser findFirstByOrderByUnameAsc(); SystemUser findTopByOrderByUnameAsc(); Page<SystemUser> queryFirst10ByUname(String uname); Slice<SystemUser> findTop3ByUname(String uname); List<SystemUser> findFirst10ByUname(String uname); List<SystemUser> findTop3ByUname(String uname);
查询方法的结果可以通过关键字来限制first或top,其可以被互换地使用,可选数值可以追加到顶部/第一个以指定要返回的最大结果大小,如果被省略,则假设结果大小为1,支持Distinct关键字
查询结果的不同形式
1.流式查询结果
可以通过使用Java 8 Stream<T> 作为返回类型来逐步处理查询方法的结果
dao:
@Query("select u from t_user u")
Stream<SystemUser> findAllByStream();
测试代码:
@Test // 一定要设置transaction,否则InvalidDataAccessApiUsageException // 如果对流没有写的操作建议将readonly 设置为 true @Transactional public void testStream() { Stream<SystemUser> systemUserStream = null; try { systemUserStream = this.userRepository.findAllByStream(); systemUserStream.forEach(System.out::println); } catch (Exception e) { e.printStackTrace(); } finally { // 使用完后关闭流 if (systemUserStream != null){ systemUserStream.close(); } } }
2.异步查询结果
使用Spring的异步方法执行功能异步的存储库查询
在调用时立即返回,并且实际的查询执行将发生在已提交给Spring TaskExecutor的任务中
比较适合定时任务的实际场景
@Async Future<SystemUser> findByUname(String uname); @Async CompletableFuture<SystemUser> findOneByUname(String uname); @Async ListenableFuture<SystemUser> findOneByUnameAndEmail(String uname,String email);
Projections 对查询结果的扩展
Projections扩展支持: 指的是和DB查询结果的字段映射关系
一般情况下返回的字段和DB查询结果的字段是一一对应的,但有的时候我们需要返回一些特定的字段,不需要全部返回,或者返回一些复合型的字段,还要自己写逻辑
正常写法如下:
@Entity(name = "t_user") @Data public class SystemUser { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String uname; private String email; private String address; }
仅仅返回实体类中的uname字段和email字段:
映射对象(entity)写法如下:
public interface NameEmailOnly { String getUname(); String getEmail(); }
dao写法如下:
public interface UserRepository extends JpaRepository<SystemUser,Long> { Collection<NameEmailOnly> findByUname(String uname); }
映射实体类支持用 Spring 中 @Value和SPEL
public interface NameEmailOnly { @Value("#{target.uname + ' ' + target.email}") String getUname(); }
映射实体还可以使用如下这种自定义计算:
@Component class MyBean{ public String getUname(SystemUser systemUser){ // 自定义计算 return systemUser.getUname() + "#" + systemUser.getAddress(); } } public interface NameEmailOnly { @Value("#{@myBean.getUname(target)}") String getUname(); }
不仅仅可以使用interface 还支持Dto实体:
@Data public class NameEmailOnlyDto { String uname; String email; // 必须要用全字段的构造方法,lombok中的@AllArgsConstructor public NameEmailOnlyDto(String uname, String email) { this.uname = uname; this.email = email; } }
支持动态Projections
dao写法:
public interface UserRepository extends JpaRepository<SystemUser,Long> { <T> Collection<T> findByUname(String uname,Class<T> type); }
测试代码:
@Test public void testProjections(){ Collection<SystemUser> systemUsers = this.userRepository.findByUname("zhangsan",SystemUser.class); System.out.println(systemUsers); }

浙公网安备 33010602011771号