Spring Data Repository
Spring Data Repository 抽象的目的是为了减少实现各种持久化存储的方法所需的样板式代码。
Spring Data 的核心抽象是 Repository,通过 类 与 类ID 进行管理。
一、Repository 的实现接口
1. CrudRepository
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);
// 根据ID查询
Optional<T> findById(ID var1);
// 判断ID对应的实体是否存在
boolean existsById(ID var1);
// 查询所有
Iterable<T> findAll();
// 根据ID集合查询
Iterable<T> findAllById(Iterable<ID> var1);
// 实体总数
long count();
// 删除
void deleteById(ID var1);
// 删除给定实体
void delete(T var1);
// 根据ID集合删除
void deleteAll(Iterable<? extends T> var1);
// 删除所有
void deleteAll();
}
2. PagingAndSortingRepository
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
// 带条件排序的查询
Iterable<T> findAll(Sort var1);
// 带分页排序的查询
Page<T> findAll(Pageable var1);
}
3. ElasticsearchRepository
public interface ElasticsearchRepository<T, ID> extends ElasticsearchCrudRepository<T, ID> {
<S extends T> S index(S var1);
<S extends T> S indexWithoutRefresh(S var1);
Iterable<T> search(QueryBuilder var1);
Page<T> search(QueryBuilder var1, Pageable var2);
Page<T> search(SearchQuery var1);
Page<T> searchSimilar(T var1, String[] var2, Pageable var3);
void refresh();
Class<T> getEntityClass();
}
二、与其他 Spring Data 一起使用
2.1 多存储库示例
interface JpaPersonRep extends JpaRepository<Person, Long> { ... }
interface MongoPersonRep extends MongoRepository<Person, Long> { ... }
/**
* @Entity 为 Jpa 注释
* @Document 为 MongoDB/Elasticsearch 注释
*/
@Entity
@Document
class Person {
// getter and setter
}
2.2 配置驱动
@EnableJpaRepositories(basePackages = "com.xxx.www.jpa")
@EnableMongoRepositories(basePackages = "com.xxx.www.mongo")
class Configuration { ... }
三、查询方法
3.1 查询策略
可以使用 @Enable${store}Repositories 的 queryLookupStrategy 属性来定义查询策略,具体策略如下:
CREATE- 尝试从查询的方法名称中构造出查询条件- 通常是从方法名中删除
findBy、findAll等特定前缀,然后解析剩余部分
- 通常是从方法名中删除
USE_DECLARED_QUERY- 尝试查找已声明的查询,如果找不到则抛出异常。CREATE_IF_NOT_FOUND- 默认,组合CREATE与USE_DECLARED_QUERY。首先查找一个声明的查询,其次创建一个基于名称的方法查询,最后才是抛出异常。
3.2 查询方式
从方法名创建,该机制的前缀如
find...By,read...By,query...By和get...By开始解析其余部分。实体查询的条件从
By开头,并以And和Or连接。还可以使用Between,LessThan,GreaterThan和Like等表达式。方法解析器支持
IgnoreCase属性忽略大小写,如findByNameIgnoreCase(...)忽略单个属性,和findByNameAndAgeAllIgnoreCase(...)忽略所有属性。还可以通过
OrderBy子句来排序。
3.3 特殊参数处理
查询方法还支持 Pageable 、Slice 和 Sort。
3.4 限制查询结果
可以使用 first 、 top 、Distinct 、Optional 来限制查询方法的结果。
3.5 方法返回集合或可迭代对象
可以用 Streamable 替代 Iterable 或任何集合类型。
interface PersonRepository extends Repository<Person, Long> {
Streamable<Person> findByFirstnameContaining(String firstname);
Streamable<Person> findByLastnameContaining(String lastname);
}
Streamable<Person> result = repository.findByFirstnameContaining("av")
.and(repository.findByLastnameContaining("ea"));
3.6 处理 Null 值
- 方法可返回的包装器类型:
Java8 的 Optional,com.google.common.base.Optional,scala.Option,io.vavr.control.Option。 - 可空性注释:
@NonNullApi,@NonNull,@Nullable,可用于方法上,也可用于方法参数。
3.7 异步查询结果
异步查询,意味着方法在调用时立即返回,而实际的查询执行发生在已提交给Spring的 TaskExecutor 任务中。
// 使用 `java.util.concurrent.Future` 作为返回类型
@Async
Future<User> findByFirstname(String firstname);
// 使用 `java.util.concurrent.CompletableFuture` 作为返回类型
@Async
CompletableFuture<User> findOneByFirstname(String firstname);
// 使用 `org.springframework.util.concurrent.ListenableFuture` 作为返回类型
@Async
ListenableFuture<User> findOneByLastname(String lastname);