持久化实体

本节介绍如何使用 Spring Data JPA 持久化(保存)实体。spring-doc.cadn.net.cn

保存实体

保存实体可以通过 CrudRepository.save(…) 方法来完成。该方法使用底层的 JPA EntityManager 对给定实体进行持久化或合并。如果该实体尚未被持久化,Spring Data JPA 会调用 entityManager.persist(…) 方法来保存实体;否则,它会调用 entityManager.merge(…) 方法。spring-doc.cadn.net.cn

实体状态检测策略

Spring Data JPA 提供了以下策略来检测一个实体是否为新实体:spring-doc.cadn.net.cn

  1. 版本属性和ID属性检查(默认): 默认情况下,Spring Data JPA 首先检查是否存在一个非基本类型的版本(Version)属性。 如果存在,则当该属性的值为 null 时,该实体被视为新实体。 如果没有这样的版本属性,Spring Data JPA 将检查给定实体的标识符(identifier)属性。 如果标识符属性为 null,则该实体被假定为新实体。 否则,则假定该实体不是新实体。 与其他 Spring Data 模块不同,JPA 将 0(零)视为实体首次插入时的版本号,因此不能使用基本类型的版本属性来判断实体是否为新实体。spring-doc.cadn.net.cn

  2. 实现 Persistable:如果一个实体实现了 Persistable 接口,Spring Data JPA 会将新实体的检测委托给该实体的 isNew(…) 方法。 详情请参见 JavaDocspring-doc.cadn.net.cn

  3. 实现 EntityInformation:您可以通过创建 EntityInformation 的子类并相应地重写 SimpleJpaRepository 方法,来自定义 JpaRepositoryFactory 实现中使用的 getEntityInformation(…) 抽象。然后,您需要将自定义的 JpaRepositoryFactory 实现注册为 Spring Bean。请注意,这种情况通常很少需要。详情请参见 JavaDocspring-doc.cadn.net.cn

选项1不适用于使用手动分配标识符且没有版本属性的实体,因为这类实体的标识符始终不会为null。 在这种情况下,一种常见的模式是使用一个公共基类,其中包含一个瞬态(transient)标志,默认表示该实例为新实例,并利用JPA生命周期回调在持久化操作时翻转该标志:spring-doc.cadn.net.cn

示例 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…
}
1 声明一个标志来保存新状态。使用 transient 关键字,使其不会被持久化到数据库中。
2 Persistable.isNew() 的实现中返回该标志,以便 Spring Data 仓库知道是调用 EntityManager.persist() 还是 ….merge()
3 声明一个使用 JPA 实体回调的方法,以便在调用仓库的 save(…) 方法或由持久化提供者创建实例后,将标志切换为指示该实体已存在。