持久化实体
本节介绍如何使用 Spring Data JPA 持久化(保存)实体。
保存实体
保存实体可以通过 CrudRepository.save(…) 方法来完成。该方法使用底层的 JPA EntityManager 对给定实体进行持久化或合并。如果该实体尚未被持久化,Spring Data JPA 会调用 entityManager.persist(…) 方法来保存实体;否则,它会调用 entityManager.merge(…) 方法。
实体状态检测策略
Spring Data JPA 提供了以下策略来检测一个实体是否为新实体:
-
版本属性和ID属性检查(默认): 默认情况下,Spring Data JPA 首先检查是否存在一个非基本类型的版本(Version)属性。 如果存在,则当该属性的值为
null时,该实体被视为新实体。 如果没有这样的版本属性,Spring Data JPA 将检查给定实体的标识符(identifier)属性。 如果标识符属性为null,则该实体被假定为新实体。 否则,则假定该实体不是新实体。 与其他 Spring Data 模块不同,JPA 将0(零)视为实体首次插入时的版本号,因此不能使用基本类型的版本属性来判断实体是否为新实体。 -
实现
Persistable:如果一个实体实现了Persistable接口,Spring Data JPA 会将新实体的检测委托给该实体的isNew(…)方法。 详情请参见 JavaDoc。 -
实现
EntityInformation:您可以通过创建EntityInformation的子类并相应地重写SimpleJpaRepository方法,来自定义JpaRepositoryFactory实现中使用的getEntityInformation(…)抽象。然后,您需要将自定义的JpaRepositoryFactory实现注册为 Spring Bean。请注意,这种情况通常很少需要。详情请参见 JavaDoc。
选项1不适用于使用手动分配标识符且没有版本属性的实体,因为这类实体的标识符始终不会为null。
在这种情况下,一种常见的模式是使用一个公共基类,其中包含一个瞬态(transient)标志,默认表示该实例为新实例,并利用JPA生命周期回调在持久化操作时翻转该标志:
@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…
}
| 1 | 声明一个标志来保存新状态。使用 transient 关键字,使其不会被持久化到数据库中。 |
| 2 | 在 Persistable.isNew() 的实现中返回该标志,以便 Spring Data 仓库知道是调用 EntityManager.persist() 还是 ….merge()。 |
| 3 | 声明一个使用 JPA 实体回调的方法,以便在调用仓库的 save(…) 方法或由持久化提供者创建实例后,将标志切换为指示该实体已存在。 |