我的 Spring Boot 应用程序使用 a.o. 2 个实体类。实体类 1 使用使用序列的技术 key id。该实体包含其他实体的列表,因此是一对多。子实体使用相同的序列。
使用 20 的序列分配(缓存)大小,我发现出现 EntityExistsException:
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [nl.xyz.app1.entity.ChildFields #123456]
实体是:
@Entity
@Table(name = "CHILD_FIELDS")
public class ChildFields implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "my_entity_seq_gen")
@SequenceGenerator(name = "my_entity_seq_gen", sequenceName = "MYSEQ_S01")
@Column(name = "CF_ID", unique = true, nullable = false)
private Long id;
@Column(name = "CF_DETAILS_ID")
private Long detailsId;
和
@Entity
@Table(name = "PARENTS_OBJECT")
public class ParentObject implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "my_entity_seq_gen")
@SequenceGenerator(name = "my_entity_seq_gen", sequenceName = "MYSEQ_S01")
@Column(name = "PF_ID", unique = true, nullable = false)
private Long id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "CF_DETAILS_ID")
private List<ChildFields> children;
当我使用分配序列1时,一切正常! 为什么是这样?
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "my_entity_seq_gen" )
@SequenceGenerator(name = "my_entity_seq_gen", sequenceName = "MYSEQ_S01", allocationSize=1)
等等。
最佳答案
将 JPA 与 DB 序列结合使用时要小心。解决方案是使用 allocateSize 为 1。我使用 Oracle 和 Progress 对此进行了测试。
您可以通过 this post 找到很好的解释。 Puspender Tanwar,给出了详尽的解释!
通过将 Sequence IncrementBy 值更改为我在 JPA 的 AllocationSize 中设置的值解决了该问题。
CREATE SEQUENCE "APPS"."LINE_LOCQTY_JPA_ID_SQ" MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 20 START WITH 7641 CACHE 20 NOORDER NOCYCLE ;
对上一个序列(IncrementBy value 1)问题的解释:
- 当 JPA 需要 Id 值时,它会访问 DB Sequence 并请求唯一值,Sequence 返回 7641。
- 现在 JPA 有了一个 ID 起点,并且基于 AllocationSize=20,JPA 自行创建接下来的 20 个值并生成 7641 到 7660 个唯一 ID。
- 现在,当所有这些 ID 都被使用时,JPA 会向 DB Sequence 询问下一个唯一值。由于最后返回的值为 7641,因此序列返回 7642(因为 INCRMENTBY 值为 1)。
- JPA 获取 7642 并在缓存中创建接下来的 20 个值。
- 当 JPA 尝试将这些值分配给 ID 时,它发现 7642 已经分配给实体对象(在步骤 2 中)。
INCRMENTBY 20 如何解决该问题:当 Id 在第 3 步被消耗时,JPA 会请求 Sequence 的下一个值。上次返回的值是 7641,因此这次它将增加 20 并返回 7661。JPA 创建从 7661 到 7680 的值并使用它们。因此不存在独特的 key 违规问题。
关于java - Spring JPA - 序列缓存会产生意想不到的行为。使用分配大小 = 1 就可以了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54786432/