持久化实体
本节介绍如何使用 Spring Data JPA 持久化(保存)实体。
保存实体
保存实体可以通过 CrudRepository.save(…)
方法执行。它使用底层的 JPA EntityManager
来持久化或合并给定的实体。如果实体尚未被持久化,Spring Data JPA 会通过调用 entityManager.persist(…)
方法来保存该实体。否则,它会调用 entityManager.merge(…)
方法。
实体状态检测策略
Spring Data JPA 提供了以下策略来检测一个实体是否是新的:
-
版本属性和标识符属性检查(默认):默认情况下,Spring Data JPA 首先检查是否存在非原始类型的版本属性。如果存在,当该属性的值为
null
时,实体被视为新的。如果没有这样的版本属性,Spring Data JPA 会检查给定实体的标识符属性。如果标识符属性为null
,则假定实体是新的。否则,假定实体不是新的。 -
实现
Persistable
:如果实体实现了Persistable
,Spring Data JPA 将新实体检测委托给实体的isNew(…)
方法。详情请参阅 JavaDoc。 -
实现
EntityInformation
:您可以通过创建JpaRepositoryFactory
的子类并相应地重写getEntityInformation(…)
方法来自定义SimpleJpaRepository
实现中使用的EntityInformation
抽象。然后,您需要将JpaRepositoryFactory
的自定义实现注册为 Spring bean。请注意,这种情况很少需要。详情请参阅 JavaDoc。
对于使用手动分配标识符且没有版本属性的实体来说,选项 1 并不是一个可行的选择,因为在这种情况下,标识符始终是非 null
的。在这种场景中,常见的模式是使用一个带有瞬态标记的通用基类,该标记默认表示一个新实例,并在持久化操作中使用 JPA 生命周期回调来翻转该标记:
示例 1. 一个用于具有手动分配标识符的实体的基类
@MappedSuperclass
public abstract class AbstractEntity<ID> implements Persistable<ID> {
@Transient
private boolean isNew = true; 1
@Override
public boolean isNew() {
return isNew; 2
}
@PrePersist 3
@PostLoad
void markNotNew() {
this.isNew = false;
}
// More code…
}
声明一个标志来保存新的状态。使用
transient
修饰,以便它不会被持久化到数据库中。在
Persistable.isNew()
的实现中返回该标志,以便 Spring Data 仓库知道是调用EntityManager.persist()
还是….merge()
。使用 JPA 实体回调声明一个方法,以便在仓库调用
save(…)
或持久化提供者创建实例后,该标志被切换为指示现有实体。