this question 提交保存 entity2entity3 实例的事务中,每个实例都持有对 Entity1 (entity1) 实例的引用,导致 entity1 的两条记录出现在数据库中(因为在保存每个实例时会保存引用)。

如果我有 2 个 Spring Data Repositories - Entity2RepositoryEntity3Repository 并且我执行以下操作将导致数据库中包含实体 1 的 2 个实例:

Entity1 entity1 = new Entity1();
entity1.name = "Name1";
entity1.value = "Value1";

Entity2 entity2 = new Entity2();
entity2.name = "Name2";
entity2.value = "Value2";
entity2.setEntity1(entity1);

Entity3 entity3 = new Entity3();
entity3.name = "Name3";
entity3.value = "Value3";
entity3.setEntity1(entity1);

Entity2Repository.save(entity2);
Entity3Repository.save(entity3);

最佳答案

简答

它将正常工作(仅生成 entity1 的一条记录)。

长答案

示例代码执行的实际结果取决于测试方法上是否存在 @Transactional 注释。

Entity2Repository.save(entity2);
Entity3Repository.save(entity3);

这些调用将调用 SimpleJpaRepository#save() 方法,它是 @Transactional 本身。
@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

此外,如您所见,您不应该担心持久/合并调用 - 如果它是一个新实体,则会调用 persist()isNew() 检查非常简单(参见 AbstractPersistable 源代码):
public boolean isNew() {
    return null == getId();
}

没有@Transactional

将有两个事务 - 每个 save() 调用一个。
  • entity1 , entity2entity3 TRANSIENT 现在是
  • Entity2Repository.save(entity2) 被调用
  • 事务打开, session 创建
  • persist()entity2 调用,因为它是新实体
  • persist() 级联到 entity1
  • entity1entity2 现在是 PERSISTENT ,它们附加到
    当前 session
  • 事务提交, session 关闭
  • entity1entity2 DETACHED 现在是
  • Entity3Repository.save(entity3) 被调用
  • 事务已打开, session 已创建
  • persist()entity3 调用,因为它是新实体
  • persist() 级联到 entity1
  • org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist 被抛出
  • 事务回滚, session 关闭
  • entity1entity2 条目保存在数据库中。

    与@Transactional

    默认情况下@Transactional 传播是 REQUIRED - 只有一个事务。
  • entity1 , entity2entity3 TRANSIENT 现在是
  • 事务打开, session 创建
  • Entity2Repository.save(entity2) 被调用
  • persist()entity2 调用,因为它是新实体
  • persist() 级联到 entity1
  • entity1entity2 现在是 PERSISTENT ,它们附加到当前 session
  • Entity3Repository.save(entity3) 被调用
  • persist()entity3 调用,因为它是新实体
  • persist() 级联到 entity1 ,在一级缓存中找到的管理实体
  • entity3 现在是 PERSISTENT ,它附加到当前 session
  • 事务提交, session 关闭
  • entity1entity2entity3 条目保存在数据库中。

    关于java - 将 CascadeType.MERGE 与 Spring Data Repositories 一起使用的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46537455/

    10-10 11:08