java - Spring JPA - 序列缓存会产生意想不到的行为。使用分配大小 = 1 就可以了

标签 java jpa spring-data-jpa sequence id-generation

我的 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)问题的解释:

  1. 当 JPA 需要 Id 值时,它会访问 DB Sequence 并请求唯一值,Sequence 返回 7641。
  2. 现在 JPA 有了一个 ID 起点,并且基于 AllocationSize=20,JPA 自行创建接下来的 20 个值并生成 7641 到 7660 个唯一 ID。
  3. 现在,当所有这些 ID 都被使用时,JPA 会向 DB Sequence 询问下一个唯一值。由于最后返回的值为 7641,因此序列返回 7642(因为 INCRMENTBY 值为 1)。
  4. JPA 获取 7642 并在缓存中创建接下来的 20 个值。
  5. 当 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/

相关文章:

java - 保留实体,除非它们已经存在?

java - 在数据库更新时使用 Spring 和 Hibernate 更新单例对象

java - Spring Data JPA - 转义重音法语字符(é,à,è,û..)

java - 当我可以在 Spring JPA 中编写方法时为什么还需要 @Query

java - Facebook Android sdk 和 Facebook 应用重叠

java - 如何使我的 jframe 可滚动而不删除文本

java - 如何在Scala中实现扩展Comparable且没有特定类型的Java接口(interface)?

java - Java中通过执行ping命令来检测网络上的设备

java - Hibernate中使用@OneToOne进行select时遇到java.lang.StackOverflowError

java - 无法在mysql中使用spring data jpa创建表