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
属性是唯一标识; -
name
和age
是值,用来描述实体Person
; -
同样
address
和children
也是用来描述某个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); //根据分野参数查询出所有的实体 }
针对不同的数据库,也有特定的子接口抽象,如:JpaRepository
、ElasticsearchRepository
等。
我们可以通过继承上面的接口来定义实体的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...By
、read...By
、get…By
,By
之后是查询条件(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
之前还可以用通过firtst
、top
关键字来限制查询数量:
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