持久化实体
本节介绍如何使用 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,则认为实体是新建的;否则认为不是新建的。与其他 Spring Data 模块不同,JPA 将0(零)视为实体插入的第一个版本,因此基本类型的版本属性不能用于判断实体是否为新建。 -
实现
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
}
@PostPersist 3
@PostLoad
void markNotNew() {
this.isNew = false;
}
// More code…
}
声明一个标志来保存新建状态。将其设为瞬态,使其不被持久化到数据库。
在
Persistable.isNew()的实现中返回该标志,以便 Spring Data 仓库知道应调用EntityManager.persist()还是….merge()。使用 JPA 实体回调声明一个方法,以便在仓库调用
save(…)或持久化提供方创建实例之后,将该标志切换为表示已存在的实体。