6.2 Spring Data JPA基础接口

1. CrudRepository

仅提供一些相对简单的增删改查方法。
源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
}

2. PagingAndSortingRepository

继承了CrudRepository,除了基本的增删改查外,还提供了排序和分页的方法。
源码:

1
2
3
4
5
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}

简单介绍用法:接口继承之后,直接使用如下方法即可完成调用。
需要注意的是,页码要从0开始…

1
2
Sort sort = new Sort(Sort.Direction.DESC,"id");
Page<Book> page = bookRepository.findAll(PageRequest.of(0,2,sort));

3. JpaRepository

前面两个接口是SpringData中比较底层的接口,兼容NoSQL,从JpaRepository开始,则对关系型数据库进行了优化,批量操作、手动刷新数据库、返回List等。
源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
<S extends T> List<S> findAll(Example<S> example);
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

4. SimpleJpaRepository

JpaRepository的实现类,主要通过Hibernate的EntityManager实现。
部分源码:

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
31
32
33
34
35
36
37
38
39
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
private final JpaEntityInformation<T, ?> entityInformation;
private final EntityManager em;
private final PersistenceProvider provider;
//...
@Transactional
public void delete(T entity) {
Assert.notNull(entity, "The entity must not be null!");
em.remove(em.contains(entity) ? entity : em.merge(entity));
}

@Transactional
public void flush() {
em.flush();
}

@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
public Optional<T> findById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return Optional.ofNullable(em.find(domainType, id));
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}
//...
}

具体继承哪一个接口还是根据实际业务决定的。