Spring Data JPA最大的特色就是利用方法名定义查询方法完成CURD操作。Spring Data JPA 的 Defining Query Methods(DQM)通过方法名和参数,可以很好地解决上面的问题,也能让我们的方法名的语义更加清晰,开发效率也会提升很多。DQM 语法共有 2 种,可以实现上面的那些问题,具体如下:
- 一种是直接通过方法名就可以实现,这也是本课时会详细介绍的重点内容;
- 另一种是 @Query 手动在方法上定义;
定义查询方法的配置和使用方法
若想要实现 CRUD 的操作,常规做法是写一大堆 SQL 语句。但在 JPA 里面,只需要继承 Spring Data Common 里面的任意 Repository 接口或者子接口,然后直接通过方法名就可以实现。
该语法是:带查询功能的方法名由查询策略(关键字)+ 查询字段 + 一些限制性条件组成,具有语义清晰、功能完整的特性。你知道Spring Data JPA是如何解析方法名成SQL的么?参考一下org.springframework.data.repository.query.parser.PartTree。
所以我们在写SQL的时候,如果不知道支持哪些语法可以参考这两个类。
特定类型的参数:Sort 排序和 Pageable 分页
Spring Data JPA 为了方便我们排序和分页,支持了两个特殊类型的参数:Sort 和 Pageable。
//查询user里面的lastname=jk的第一页,每页大小是20条;并会返回一共有多少页的信息
Page<User> users = userRepository.findByLastname("jk",PageRequest.of(1, 20));
//查询user里面的lastname=jk的第一页的20条数据,不知道一共多少条
Slice<User> users = userRepository.findByLastname("jk",PageRequest.of(1, 20));
//查询出来所有的user里面的lastname=jk的User数据,并按照name正序返回List
List<User> users = userRepository.findByLastname("jk",new Sort(Sort.Direction.ASC, "name"))
//按照createdAt倒序,查询前一百条User数据
List<User> users = userRepository.findByLastname("jk",PageRequest.of(0, 100, Sort.Direction.DESC, "createdAt"));
限制查询结果 First 和 Top
有的时候我们想直接查询前几条数据,也不需要动态排序,那么就可以简单地在方法名字中使用 First 和 Top 关键字,来限制返回条数。
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
List<User> findDistinctUserTop3ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
方法的查询策略设置
我们知道在JPA查询的时候即可以使用方法名进行查询,也可以使用@Query进行查询,那么JPA的选择策略是什么?你可能会想到,如果存在@Query会优先使用注解形式进行查询。其实JPA给我们提供了选择查询策略。
@EnableJpaRepositories(queryLookupStrategy= QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND)
其中,QueryLookupStrategy.Key 的值共 3 个,具体如下:
- Create:直接根据方法名进行创建,规则是根据方法名称的构造进行尝试,一般的方法是从方法名中删除给定的一组已知前缀,并解析该方法的其余部分。如果方法名不符合规则,启动的时候会报异常,这种情况可以理解为,即使配置了 @Query 也是没有用的。
- USE_DECLARED_QUERY:声明方式创建,启动的时候会尝试找到一个声明的查询,如果没有找到将抛出一个异常,可以理解为必须配置 @Query。
- CREATE_IF_NOT_FOUND:这个是默认的,除非有特殊需求,可以理解为这是以上 2 种方式的兼容版。先用声明方式(@Query)进行查找,如果没有找到与方法相匹配的查询,那用 Create 的方法名创建规则创建一个查询;这两者都不满足的情况下,启动就会报错。
思考
repository是属于dao层,严格意义上来说需要经过Service包装之后才能被使用,那么如果让Service具有通用的CURD能力呢?