Spring Boot 2.x实战 - Spring Data 1 - DDD与Spring Data(Repository)

Spring Data 是一个伞型项目,包含主流的数据库的访问技术。这些不同的数据访问项目都使用相同的编程模型,他们都是基于Repository规范接口。我们在本章选关系型数据库的访问技术Spring Data JPA和NoSQL的访问Spring Data Elasticsearch。

1. Spring Data Repository

1.1 DDD与Spring Data

1.1.1 DDD

DDD是Domain-Driven Design的缩写,即领域驱动设计。它是解决复杂业务需求的一些列高级技术。

它的战术设计部分有几个重要概念和Spring Data有关系:

  • 实体(Entity):对一个实际的事物进行抽象建模,每一个实体都有唯一标识用来和其他的实体做为区别;实体是可变的,它会随着时间的推移而修改。
  • 值对象(Value Object):值对象等同于值,它对一个不变的概念的整体进行建模。它没有唯一标识,相等性通过比较值对象的属性来实现;值对象不能被修改只能被替换;它和值一样都是用来描述、量化或衡量实体的。
  • 聚合(Aggregate):聚合是一个或多个实体组合而成的,其中表示核心概念的实体叫做聚合根。在实际设计中有“设计小聚合的原则”,一般情况下一个聚合只包含一个实体类。
  • 领域事件(Domain Event):聚合之间的通讯通过发布领域事件来进行,事件由聚合根发布。
  • 库(Repository):Respository是用来存储聚合的,每一个聚合都有一个Respository,它们之间是一对一的关系。库中对聚合的存储操作类似于集合类,和Set一样保证数据的唯一性。

我们先举例说明上面的概念:

public class Person {
    private Long id;
    private String name;
    private Integer age;
    private Address address;
    private Collection<Child> children;
      //...
}
  • Person是实体类,因为设计小聚合的原则,Person也是聚合与聚合根;

  • id属性是唯一标识;

  • nameage是值,用来描述实体Person

  • 同样addresschildren也是用来描述某个Person的,是对象形式的,所以它们是值对象。

1.1.2 Spring Data Repository

Spring Data Repository对访问不同的数据库提供统一的抽象,它极大的减少了数据访问层的样板代码。Spring Data Repository抽象的核心是org.springframework.data.repository.Repository<T, ID>T代表是它处理的实体的类型,ID代表实体的唯一标识。它的主要子接口有CrudRepository定义新增、查询、更新、删除功能接口。PagingAndSortingRepository又是CrudRepository的子接口,定义了分页和排序的功能接口。

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); // 按照id查询实体
   boolean existsById(ID id); // 按照id查询的实体是否存在
   Iterable<T> findAll();     //查出所有实体
   Iterable<T> findAllById(Iterable<ID> ids); //按照多个id查询多个实体
   long count(); //计数实体
   void deleteById(ID id); //按照id删除实体
   void delete(T entity); //删除实体
   void deleteAll(Iterable<? extends T> entities);//删除多个实体
   void deleteAll(); //删除所有实体
}
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
   Iterable<T> findAll(Sort sort); //根据排序参数查询出所有的实体
   Page<T> findAll(Pageable pageable); //根据分野参数查询出所有的实体
}

针对不同的数据库,也有特定的子接口抽象,如:JpaRepositoryElasticsearchRepository等。

我们可以通过继承上面的接口来定义实体的Repository,并通过相关的开启配置(@EnableJpaRepositories)的注解后,实体Repository会被Spring Data注册成为一个Bean,我们可以使用这个Bean进行数据访问操作了。

定义Repository:

public interface PersonRepository extends JpaRepository<Person, Long> {
}

使用Repository:

@RestController
@RequestMapping("/people")
public class PersonController {

    private PersonRepository personRepository;

    public PersonController(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    @GetMapping("/findByName")
    public List<Person> findByName(@RequestParam String name){
        return personRepository.findByName(name);
    }
}

我们用相应注解将相应数据库的领域模型标识为实体,如:JPA使用的是@Entity,Elasticsearch使用的是@Document

JPA:

@Entity
public class Person {
    @Id
    private Long id;
    private String name;
    private Integer age;
    //...
}

Elasticsearch:

@Document(indexName = "person")
public class Person {}

1.2 查询方法

Spring Data支持根据方法名中的属性进行推导查询,关键词可以是find...Byread...Byget…ByBy之后是查询条件(where 之后的条件)

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> findByName(String name);
      List<Person> findDistinctPersonByName(String name);
}

也可通过count...By进行推导计数查询:

public interface PersonRepository extends JpaRepository<Person, Long> {
    long countByName(String name);
}

也可通过delete...By进行推导删除查询:

public interface PersonRepository extends JpaRepository<Person, Long> {
    long deleteByName(String name);
    List<Person> removeByName(String name);
}

By之前还可以用通过firtsttop关键字来限制查询数量:

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> queryTop5ByName(String name);
    List<Person> getFirst10ByName(String name);
}

 

 

转自:https://blog.csdn.net/wiselyman/article/details/106227455

posted @ 2020-10-14 15:21  十月围城小童鞋  阅读(426)  评论(0编辑  收藏  举报