第四章 Spring Data JPA 进阶

关于 Repository 接口

Repository 讲解

  • Repository 接口是 Spring Data 的核心接口,不提供任何方法
  • public interface Repository<T,ID extends Serializable> { }
  • @RepositoryDefinition 注解的使用

Repository是一个空接口,标记接口 没有包含方法声明的接口

@RepositoryDefinition 注解的使用

1
2
3
4
5
6
7
8
9
10
/**
* @author weilai
* @version 1.0.0 2018/8/23
*/
@RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)
public interface EmployeeRepository { // extends Repository<Employee, Integer> {

public Employee findByName(String name);

}

Repository 子接口详解

  • CrudRepository:
    • 继承 Repository,实现了 CRUD 相关的方法。
  • PagingAndSortingRepository:
    • 继承 CrudRepository,实现了 分页和排序 相关的方法。
  • JpaRepository:
    • 继承 PagingAndSortingRepository,实现了 JPA 相关的方法。

查询方法定义规则和使用

Repository 中查询方法定义规则和使用

Keyword Sample JPQL snippet
And findByLastnameAndFirstname where
x.lastname = ?1
and
x.firstname = ?2
Or findByLastnameOrFirstname where
x.lastname = ?1
or
x.firstname = ?2
Between findByStartDataBetween where
x.startData between
?1 and ?2
LessThan findByAgeLessThan where x.age < ?1
GreaterThan findByAgeGreaterThan where x.age > ?1
After findByStartDataAfter where x.startData > ?1
Before findByStartDataAfter where x.startData > ?1
IsNull findByAgeIsNull where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull where x.age is not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

操作实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.imooc.repository;

import com.imooc.domain.Employee;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;

import java.util.List;


/**
* 数据操作实体
*
* @author weilai
* @version 1.0.0 2018/8/23
*/
@RepositoryDefinition(domainClass = Employee.class, idClass = Integer.class)
public interface EmployeeRepository { // extends Repository<Employee, Integer> {

public Employee findByName(String name);

// where name like ?% and age <?
public List<Employee> findByNameStartingWithAndAgeLessThan(String name, Integer age);

// where name like ?% and age >?
public List<Employee> findByNameEndingWithAndAgeLessThan(String name, Integer age);

// where name in (?,?,?....) or age >?
public List<Employee> findByNameInOrAgeLessThan(List<String> nameList, Integer age);

}

对于按照方法命名规则来使用的话,有弊端:

  1. 方法名会比较长: 约定大于配置
  2. 对于一些复杂的查询,是很难实现

Query注解使用

  • 在 Repository 方法中使用,不需要遵循查询方法命名规则
  • 只需要将 @Query 定义在 Repository 方法上
  • 命名参数及索引参数的使用 ?1 ?2 :name :age 占位符
  • 本地查询(@Query(nativeQuery = true,value = “select count(1) from employee”)) 开启 nativeQuery 使用原生 SQL 进行查询

更新操作整合事务使用

  • @Modifying 注解使用
  • @Modifying 结合 @Query 注解执行更新操作

事务在Spring data中的使用:

  1. 事务一般是在Service层作注解
  2. @Query、 @Modifying、@Transactional的综合使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@Query(nativeQuery = true, value = "select count(1) from employee") // 注意!!此处 employee 是表名
public long getCount();

@Modifying
@Query("update Employee o set o.age = :age where o.id = :id") // 注意!!此处 Employee 是类名
public void update(@Param("id") Integer id, @Param("age") Integer age);

...
@Service
public class EmployeeService {
@Transactional
public void update(Integer id, Integer age) {
employeeRepository.update(id, age);
}
}
...

一般在 Service 的一个操作中有很多 dao方法,所以都要让他们在一个事务中。