开篇广告
自己开发的淘宝领券网站:q.hayye.cn(手机打开)
要说特色,应该没有,硬要说的话就是没广告、没推送,简单好用。
前端开源地址:https://gitee.com/hayye/tbq
后端不开源……
欢迎大家加群讨论技术,不定时也会有淘宝神券发放!
正文开始
查询方法生成策略
Spring提供了三种查询方法生成策略query-lookup-strategy。可以在<jpa:repositories />标签中进行配置,可选值分别为:
create:通过解析方法名,由Spring创建查询方法;
use-declared-query:根据注解中定义好的查询语句进行查询;若找不到语句,则抛出异常;
create-if-not-found(默认):结合上两点,先查找是否有定义的查询语句,若没有,再根据方法名创建查询。
所以一般情况下,无需配置,使用默认的即可。
定义方法名查询
在接口中定义一个方法,但方法名要按照Spring规范定义,如此,Spring便可以自动生成对应的查询方法。
示例:
public interface BookRepository extends JpaRepository<Book,Long> {
List<Book> findByBookname(String bookname);
Page<Book> findByBooknameLike(String bookname,Pageable pageable);
}
该例中对应的JPQL分别为:
select b from book b where bookname = ?1;
select b from book b where bookname like ?1 limit ?,?;
所以通过定义方法名的方式,可以实现大部分条件查询;
方法名规范:
- 前缀
一共有九种前缀后加By,在org.springframework.data.repository.query.parser.PartTree中定义。
private static final String QUERY_PATTERN = "find|read|get|query|stream";
private static final String COUNT_PATTERN = "count";
private static final String EXISTS_PATTERN = "exists";
private static final String DELETE_PATTERN = "delete|remove";
- 属性名
必须是该类中存在的属性,遵守驼峰命名法,且首字母大写,若实体内包含的实体属性需使用下划线隔开;
例子:
Person内的Address内的zipCode属性:findByAddress_ZipCode(String zipcode); - 关键字
例如Like、And、Between等、参考附表:查询方法关键字;
注解式查询
@Query
注解形式的SQL、JPQL语句。注解常用参数如下:
value:SQL或JPQL语句;
nativeQuery:是否是SQL语句,默认false,即默认为JPQL语句;
实例:
public interface BookRepository extends JpaRepository<Book,Long> {
@Query(value = "select b from Book b where b.bookname like %?1%")
Page<Book> findByBooknameLike(String bookname , Pageable pageable);
//支持@Param注解的写法
@Query("select b from Book b where b.id = :id")
Book findAllById(@Param("id")Long id);
}
默认JPQL模式下,是支持Sping提供的分页和排序方法的。在SQL模式下是不被支持的。
示例:
@Query(value = "select * from book where bookname like %?1% order by ?2 ",nativeQuery = true)
List<Book> findAllOrderBy(String bookname , String sort);
@Modifying
@Query注解只能用来查询数据,而不支持增、删、改;如果在@Query中使用insert、delete、update语句将会报错,解决办法就是@Modifying与@Query注解同时使用。
@Modifying
@Query(value = "DELETE FROM book where id = ?1 ",nativeQuery = true)
void deleteById(Long id);
@NamedQuery
预定义查询,由JPA提供,注解在实体类上,定义name和query即可。与Hibernate JPA用法稍有不同,参考以下例子:
- 在实体类上方声明预查询
@Entity
@NamedQuery(name = "Book.selectById",query = "select b from Book b where b.id = :id")
public class Book {
...
}
- 在BookRepository中对应方法
public interface BookRepository extends JpaRepository<Book,Long> {
Book selectById(@Param("id")Long id);
}
之后就是调用了。
值得注意的是几种查询方法的优先级:@Query > @NamedQuery > 定义方法名查询
附:Demo源码 https://github.com/hayye/JPADemo