细节与增强
细节
关键字使用细节
Like 与 NotLike
- 使用时,在传入查询参数时,需要用%%修饰才能够正确的查询到数据.
public void testMyDataJPA(){
List<Person> people = personRepository.findByLastNameLike("%C%") ;
// List<Person> people = personRepository.findByLastNameNotLike("%C%") ;
System.out.println(people);
}
StartingWith,EndingWith,Containing
- 使用时不需要用%%修饰.
- StartingWith:以xxx开头的数据.
- EndingWith:以xxx结尾的数据.
- Containing:包含xxx数据,同Like.
List<Person> persons = personRepository.getByLastNameStartingWithAndIdLessThan("A", 5);
System.out.println(persons);
List<Person> persons2 = personRepository.getByLastNameEndingWithAndIdLessThan("C", 40);
System.out.println(persons2);
方法解析器
- 支持IgnoreCase为各个属性(例如findByLastnameIgnoreCase(…))或支持忽略大小写的类型(String例如,通常为实例)的所有属性设置标志findByLastnameAndFirstnameAllIgnoreCase(…)。是否支持忽略大小写可能因商店而异,因此请参阅参考文档中有关特定于商店的查询方法的相关章节。
SpEL表达式
-
从Spring Data JPA 1.4版开始,我们支持在手动定义的查询中使用受限制的SpEL模板表达式@Query。在执行查询时,将根据预定义的变量集评估这些表达式。Spring Data JPA支持一个名为的变量entityName。它的用法是select x from #{#entityName} x。它插入entityName与给定存储库关联的域类型。该entityName解决如下:如果域类型已设置的name属性@Entity的注释,它被使用。否则,使用域类型的简单类名。
-
当然,您可以User直接在查询声明中使用,但这也需要您更改查询。引用#entityName将User类的潜在未来重映射到不同的实体名称(例如,通过使用@Entity(name = “MyUser”)。
@Query("select p from #{#entityName} p where p.lastName = ?1")
List<Person> findByLastNameT(String lastName) ;
可空性注释
-
您可以使用Spring Framework的可空性注释来表达存储库方法的可空性约束。它们null在运行时提供了一种工具友好的方法和选择性检查,如下所示:
-
@NonNullApi:在包级别上使用,以声明参数和返回值的默认行为是不接受或生成null值。
-
@NonNull:用于必须不是的参数或返回值null (参数上不需要,返回值@NonNullApi适用)。
-
@Nullable:用于可以的参数或返回值null。
-
Spring注释是使用JSR 305注释进行元注释的(一种休眠但广泛传播的JSR)。JSR 305元注释允许IDEA,Eclipse和Kotlin等工具供应商以通用方式提供空安全支持,而无需对Spring注释进行硬编码支持。要为查询方法启用运行时检查可空性约束,需要使用Spring的@NonNullApiin 来激活包级别的非可空性
-
一旦存在非空默认,就会在运行时验证存储库查询方法调用的可空性约束。如果查询执行结果违反了定义的约束,则抛出异常。当方法返回null但声明为非可空时(默认情况下,存储库所在的包中定义了注释)会发生这种情况。如果您想再次选择可以为空的结果,请有选择地使用@Nullable单个方法。使用本节开头提到的结果包装器类型继续按预期工作:将空结果转换为表示缺席的值。
package com.acme;
import org.springframework.lang.Nullable;
interface UserRepository extends Repository<User, Long> {
// 在执行时不产生结果的查询时抛出一个EmptyResultDataAccessException。当emailAddress为null时抛出一个IllegalArgumentException。
User getByEmailAddress(EmailAddress emailAddress);
//null执行查询时不返回结果。也接受null作为的值emailAddress
@Nullable
User findByEmailAddress(@Nullable EmailAddress emailAdress);
//Optional.empty()执行查询时不返回结果。当emailAddress为null时抛出一个IllegalArgumentException
Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress);
}
分页和排序
//方法名直接sql查询条件,参数中带有Pageable则会分页(同时可以带有排序)
Page<User> findByLastName(String lastName, Pageable pageable);
Slice<User> findByLastName(String lastName, Pageable pageable);
List<User> findByLastName(String lastName, Sort sort);
List<User> findByLastName(String lastName, Pageable pageable);
Page<Person> findByLastNameContaining(String lastName, Pageable pageable);
限制查询结果
- 查询方法的结果可以通过使用first或top关键字来限制,这些关键字可以互换使用。可以附加一个可选的数值,top或者first指定要返回的最大结果大小。如果省略该数字,则假定结果大小为1。以下示例显示如何限制查询大小:
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
//方法名直接sql查询条件,参数中带有Pageable则会分页(同时可以带有排序)
Page<User> queryFirst10ByLastName(String lastName, Pageable pageable);
Slice<User> findTop3ByLastName(String lastName, Pageable pageable);
List<User> findFirst10ByLastName(String lastname, Sort sort);
List<User> findTop10ByLastName(String lastname, Pageable pageable);
预测
-
Spring Data查询方法通常返回由存储库管理的聚合根的一个或多个实例。但是,有时可能需要根据这些类型的某些属性创建投影。Spring Data允许建模专用返回类型,以更有选择地检索托管聚合的部分视图。
-
Entity实体:
public class Person {
private Integer id ;
private String lastName ;
private String email ;
private Date birth ;
private Integer age ;
//...
现在假设我们只想检索人的姓名和邮箱。
(1)基于接口的预测:将查询结果限制为仅名称属性的最简单方法是声明一个接口,该接口公开要读取的属性的访问器方法
- 投影接口
//用于检索属性子集的投影接口
public interface LastNameAndEmailOnly {
String getLastName() ;
String getEmail() ;
}
//这里重要的一点是,此处定义的属性与聚合根中的属性完全匹配。这样做可以添加查询方法
- dao使用:
List<LastNameAndEmailOnly> findByLastName(String lastName) ;
- 可以递归使用预测。如果您还想包含一些Address信息,请为其创建一个投影接口,并从声明中返回该接口getAddress(),如以下示例所示:
interface PersonSummary {
String getLastName() ;
String getEmail() ;
AddressSummary getAddress();
interface AddressSummary {
String getCity();
}
}
(2)基于类别的预测(DTO)
- 定义投影的另一种方法是使用值类型DTO(数据传输对象),它包含应该检索的字段的属性。这些DTO类型可以与投影界面完全相同的方式使用,除了不发生代理并且不能应用嵌套投影。
如果存储通过限制要加载的字段来优化查询执行,则要加载的字段将根据公开的构造函数的参数名称确定。
以下示例显示了投影DTO:
public class PersonDTO {
private final String lastName;
private final String email;
public PersonDTO(String lastName, String email) {
this.lastName = lastName;
this.email = email;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
}
//避免投影DTO的样板代码您可以使用Project Lombok大大简化DTO的代码,
//它提供了一个@Value注释(不要与@Value之前的接口示例中显示的Spring的注释混淆)
按示例查询(QBE)
-
按示例查询非常适合几种用例:
-
使用一组静态或动态约束查询数据存储。
-
频繁重构域对象,而不必担心破坏现有查询。
-
独立于底层数据存储API工作。
-
按示例查询也有几个限制:
-
不支持嵌套或分组的属性约束,例如firstname = ?0 or (firstname = ?1 and lastname = ?2)。
-
仅支持字符串的开始/包含/结束/正则表达式匹配以及其他属性类型的精确匹配。
-
例子:
erson person = new Person();
person.setLastName("Dave");
Example<Person> example = Example.of(person);
- 示例不限于默认设置。您可以使用,为字符串匹配,空值处理和特定于属性的设置指定自己的默认值ExampleMatcher:具体参考文档
锁定
- 要指定要使用的锁定模式,可以@Lock在查询方法上使用注释,如以下示例所示:
@Lock(LockModeType.READ)
PersonDTO findByLastName(String lastName) ;
//这个方法声明将导致触发查询中配备了LockModeType的READ
审计
基本
-
Spring Data提供了复杂的支持,可以透明地跟踪创建或更改实体的人员以及更改发生的时间。要从该功能中受益,您必须为您的实体类配备审计元数据,该元数据可以使用注释或通过实现接口来定义。
-
基于注释的审计元数据
我们提供@CreatedBy和@LastModifiedBy捕捉谁创建或修改的实体以及用户@CreatedDate和@LastModifiedDate捕捉时的变化发生了。
JPA审计
- 配置:Spring Data JPA附带了一个实体监听器,可用于触发审计信息的捕获。首先,您必须注册AuditingEntityListener要用于orm.xml文件中持久性上下文中的所有实体.
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="….data.jpa.domain.support.AuditingEntityListener" />
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
- 您还可以AuditingEntityListener使用@EntityListeners注释在每个实体的基础上启用,如下所示:
@Entity
@EntityListeners(AuditingEntityListener.class)
public class MyEntity {
}