6.3 Spring Data JPA定义查询方法

查询方法生成策略

Spring提供了三种查询方法生成策略query-lookup-strategy。可以在<jpa:repositories />标签中进行配置,可选值分别为:

create:通过解析方法名,由Spring创建查询方法;
use-declared-query:根据注解中定义好的查询语句进行查询;若找不到语句,则抛出异常;
create-if-not-found(默认):结合上两点,先查找是否有定义的查询语句,若没有,再根据方法名创建查询。

所以一般情况下,无需配置,使用默认的即可。

定义方法名查询

在接口中定义一个方法,但方法名要按照Spring规范定义,如此,Spring便可以自动生成对应的查询方法。
示例:

1
2
3
4
public interface BookRepository extends JpaRepository<Book,Long> {
List<Book> findByBookname(String bookname);
Page<Book> findByBooknameLike(String bookname,Pageable pageable);
}

该例中对应的JPQL分别为:

1
2
select b from book b where bookname = ?1;
select b from book b where bookname like ?1 limit ?,?;

所以通过定义方法名的方式,可以实现大部分条件查询;

方法名规范:
  1. 前缀
    一共有九种前缀后加By,在org.springframework.data.repository.query.parser.PartTree中定义。
1
2
3
4
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";
  1. 属性名
    必须是该类中存在的属性,遵守驼峰命名法,且首字母大写,若实体内包含的实体属性需使用下划线隔开;
    例子:
    Person内的Address内的zipCode属性:findByAddress_ZipCode(String zipcode);
  2. 关键字
    例如Like、And、Between等、参考附表:查询方法关键字
原理

待完善…

注解式查询

@Query

注解形式的SQL、JPQL语句。注解常用参数如下:

value:SQL或JPQL语句;
nativeQuery:是否是SQL语句,默认false,即默认为JPQL语句;

实例:

1
2
3
4
5
6
7
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模式下是不被支持的。
示例:

1
2
@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注解同时使用。

1
2
3
@Modifying
@Query(value = "DELETE FROM book where id = ?1 ",nativeQuery = true)
void deleteById(Long id);
@NamedQuery

预定义查询,由JPA提供,注解在实体类上,定义name和query即可。与Hibernate JPA用法稍有不同,参考以下例子:

  1. 在实体类上方声明预查询
1
2
3
4
5
@Entity
@NamedQuery(name = "Book.selectById",query = "select b from Book b where b.id = :id")
public class Book {
...
}
  1. 在BookRepository中对应方法
1
2
3
public interface BookRepository extends JpaRepository<Book,Long> {
Book selectById(@Param("id")Long id);
}

之后就是调用了。

值得注意的是几种查询方法的优先级:@Query > @NamedQuery > 定义方法名查询