这就是Repostory的源码,里边没有任何方法。
- package org.springframework.data.repository;
-
- import org.springframework.stereotype.Indexed;
-
- @Indexed
- public interface Repository<T, ID> {
- }
-
但是只要继承了这个类,就可以实现JPA的一些默认实现方法。

从层级关系可以看出来分了四大类,下边简单介绍一下。
这个是响应式编程的一个类,主要支持NoSQL方面的操作。目前主要支持了Cassandra,MongoDB,Redis的实现。
这个是为了支持RxJava2做的标准响应式编程的接口。
这个是为了支持Kotlin语法而增加的
这个则是我学习的重点
我们再看一下Repository的类层级关系图:我把类的作用标注了一下。

这个接口没有默认方法,也就是说,我们增加了什么方法,就可以使用什么方法。
- public interface UserRepository extends Repository<UserInfo,Integer> {
- List<UserInfo> findByName(String name);
- List<UserInfo> findByAgeAndName(Integer age, String name);
- }
-
当我们添加了两个方法如上代码所示,一个根据name找user,一个根据age和name找用户。
这时,之前写的save和findAll方法就报错了,因为这里边没有这两个方法。

UserRepository实例通过继承Repository,使Spring容器知道UserRepository是操作数据库的类,并可以对数据库进行CRUD操作。
我们将每个方法的作用用注解进行标注,以便更直观的查看。
- @NoRepositoryBean
- public interface CrudRepository<T, ID> extends Repository<T, ID> {
- //保存
- <S extends T> S save(S var1);
- //批量保存
- <S extends T> Iterable<S> saveAll(Iterable<S> var1);
- //根据主键查询
- Optional<T> findById(ID var1);
- //根据主键查询是否存在
- boolean existsById(ID var1);
- //查询所有实体的列表
- Iterable<T> findAll();
- //根据主键的list列表查询所有实体
- Iterable<T> findAllById(Iterable<ID> var1);
- //查询总数
- long count();
- //根据主键删除
- void deleteById(ID var1);
- //根据实体类对象删除
- void delete(T var1);
- //根据主键的List删除所有
- void deleteAll(Iterable<? extends T> var1);
- //根据主键删除
- void deleteAll();
- }
-
以上这些方法就是CrudRepository对外暴露的最常见的接口,当我们的UserRepository继承CrudRepository之后,我们就可以使用这些方法操作我们的UserInfo表了。

这里我们特别看一些save和delete方法
S save(S var1);从源码可以看出,会先判断是否是新的数据,若是新的则新增,若是已有的则修改已有数据。
- @Transactional
- public
S save(S entity) { - if (this.entityInformation.isNew(entity)) {
- this.em.persist(entity);
- return entity;
- } else {
- return this.em.merge(entity);
- }
- }
-
Iterable saveAll(Iterable var1);这里可以看出,尽管是saveAll()但也是轮询然后一个一个调save方法保存的,并没有性能上的提升。
- @Transactional
- public <S extends T> List<S> saveAll(Iterable<S> entities) {
- Assert.notNull(entities, "Entities must not be null!");
- List<S> result = new ArrayList();
- Iterator var3 = entities.iterator();
-
- while(var3.hasNext()) {
- S entity = var3.next();
- result.add(this.save(entity));
- }
-
- return result;
- }
-
void deleteById(ID var1);delete方法则是先判断了传入的实体是否存在,若是不存在还抛出了错误。
- @Transactional
- public void deleteById(ID id) {
- Assert.notNull(id, "The given id must not be null!");
- this.delete(this.findById(id).orElseThrow(() -> {
- return new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", this.entityInformation.getJavaType(), id), 1);
- }));
- }
-
这个接口继承自CrudRepository,然后添加了主要用于分页查询和排序查询的两个方法。
源码如下:
- @NoRepositoryBean
- public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
- //排序查询
- Iterable<T> findAll(Sort var1);
- //分页查询
- Page<T> findAll(Pageable var1);
- }
-
这个接口只有两个方法,分别当排序和分页的时候使用。
使用的时候,直接让我们的UserRepository继承PagingAndSortingRepository即可。
- public interface UserRepository extends PagingAndSortingRepository<UserInfo,Integer> {
-
- }
-
这时查询的时候,就可以使用分页和排序了
这段代码的意思是,取第一页,每页20个数据,根据name排序。
- @GetMapping(path = "users")
- @ResponseBody
- @WebLog(printResult = true)
- public Page
getAllUsers(){ - return userRepository.findAll(PageRequest.of(1,20, Sort.by(new Sort.Order(Sort.Direction.ASC,"name"))));
- }
-
这则是根据name字段逆序排序
- @GetMapping(path = "users")
- @ResponseBody
- @WebLog(printResult = true)
- public Iterable
getAllUsers(){ - return userRepository.findAll(Sort.by(new Sort.Order(Sort.Direction.DESC,"name")));
- }