【问题标题】:Update of JPA Entity with composed PrimaryKey leads to duplicate entry error使用复合主键更新 JPA 实体导致重复输入错误
【发布时间】:2019-10-09 16:09:49
【问题描述】:

当我尝试使用 spring JpaRepository 并行存储同一个实体多次时,我得到一个重复条目,用于键 PRIMARY。 TestEntity 由两个值组成,它们经常变化,而 TestEntityId 保持不变。这个想法是使用 save 方法根据 EmbeddedId 更新 TestEntity,因为我不确定 TestEntity 是否已经存在于数据库中。

如果对于同一个 EmbeddedId 经常发生这种情况,我会很快收到重复条目错误。我还可以在单​​元测试中重现该行为。

运行测试时出现异常:java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '1-2-prov' for key 'PRIMARY'

@Entity
public class TestEntity {
    @EmbeddedId
    private TestEntityId testEntityId;
    @Column
    private String value1;
    @Column
    private String value2;
...
}
@Embeddable
public class TestEntityId implements Serializable {
    private double lat;
    private double lng;
    private String prov;
...
}
@Repository
public interface TestEntityRepository extends JpaRepository<TestEntity, TestEntityId> {
// Empty
}

测试用例

@Test
public void testStoreSameEntryMultipleTimes() {
   LongStream.range(1L, 100L).boxed().parallel()
       .map((i) -> new TestEntityId(1.0, 2.0, "prov"))
       .map((te) -> new TestEntity(te , "value1", "value2"))
       .forEach((e) -> testEntityRepository.save(e));
...
}

我已经尝试在表上添加事务或不同的锁以及其他方式来声明组合主键。

如果您对如何解决此问题有任何想法,那就太好了。

【问题讨论】:

  • 测试浮点是否相等是乞求得到灾难性的舍入错误。
  • 如果你不并行遍历流,你会得到相同的结果吗?
  • 不,它工作正常,完成后我在 DB 中有 1 个条目。不幸的是,它后来从并行运行的进程中调用,这是我在重现它之前第一次看到问题的地方。

标签: java database jpa spring-data-jpa primary-key


【解决方案1】:

问题是您要创建 100 个具有相同主键的实体,而不是使用 i 来增加它们。

【讨论】:

  • 是的,这是正确的,我喜欢创建一次,之后应该更新 99 次。从我的角度来看,保存方法能够创建和更新条目,对吗?
  • 没有。您每次都在创建新实体。如果你想更新一个旧实体,你需要从 EntityManager 中获取它,然后处理那个对象。
  • 为什么需要这个?我知道 PK 并且这个不会改变 SimpleJpaRepository 的 isNew 方法将返回 false,因为 PK 不为空。所以使用了合并功能,这会导致基于 PK 的更新对吗?
  • PK不为空,所以调用merge,而不是persist。现在在 JPA 2.1 规范 3.2.7.1 中它说 If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'。您在示例中创建了新实例,因此它被视为一个新实体。
猜你喜欢
  • 2012-10-05
  • 2015-01-24
  • 1970-01-01
  • 2011-08-17
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
相关资源
最近更新 更多