likes
comments
collection
share

Spring Data JPA渐进式学习--Repostory

作者站长头像
站长
· 阅读数 30

RepostorySpring Data Comments顶级父类接口,是操作数据库的入口类。

源码

这就是Repostory的源码,里边没有任何方法。

package org.springframework.data.repository;

import org.springframework.stereotype.Indexed;

@Indexed
public interface Repository<T, ID> {
}

但是只要继承了这个类,就可以实现JPA的一些默认实现方法。

Repostory类层次关系

Spring Data JPA渐进式学习--Repostory

从层级关系可以看出来分了四大类,下边简单介绍一下。

ReactiveCrudRepository

这个是响应式编程的一个类,主要支持NoSQL方面的操作。目前主要支持了Cassandra,MongoDB,Redis的实现。

RxJava2CrudRepository

这个是为了支持RxJava2做的标准响应式编程的接口。

CoroutineCrudRepository

这个是为了支持Kotlin语法而增加的

CrudRepository

这个则是我学习的重点

我们再看一下Repository的类层级关系图:我把类的作用标注了一下。 Spring Data JPA渐进式学习--Repostory

Repostory接口

这个接口没有默认方法,也就是说,我们增加了什么方法,就可以使用什么方法。

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方法就报错了,因为这里边没有这两个方法。

Spring Data JPA渐进式学习--Repostory

UserRepository实例通过继承Repository,使Spring容器知道UserRepository是操作数据库的类,并可以对数据库进行CRUD操作。

CrudRepository接口

我们将每个方法的作用用注解进行标注,以便更直观的查看。

@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表了。

Spring Data JPA渐进式学习--Repostory

这里我们特别看一些save和delete方法

<S extends T> S save(S var1);

从源码可以看出,会先判断是否是新的数据,若是新的则新增,若是已有的则修改已有数据。

@Transactional
public <S extends T> S save(S entity) {
    if (this.entityInformation.isNew(entity)) {
        this.em.persist(entity);
        return entity;
    } else {
        return this.em.merge(entity);
    }
}

<S extends T> Iterable<S> saveAll(Iterable<S> 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);
    }));
}

PagingAndSortingRepository接口

这个接口继承自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<UserInfo> 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<UserInfo> getAllUsers(){
    return userRepository.findAll(Sort.by(new Sort.Order(Sort.Direction.DESC,"name")));
}

下一篇文章就是激动人心的JpaRepository了,敬请期待。