【问题标题】:Old Sequence Value for JPA Generated ID using Eclipselink使用 Eclipselink 的 JPA 生成 ID 的旧序列值
【发布时间】:2016-10-21 09:05:00
【问题描述】:

当 Eclipselink 用作 ORM 时,为 JPA 实体生成的 id 会生成一个“旧”的已用数字,但使用 Hibernate 时,id 是序列的正确下一个值。 在实体类中,我将这些注释与 id 字段一起使用

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "s_customer")
@SequenceGenerator(name = "s_customer", sequenceName = "S_CUSTOMER")
private Long id;

我使用 flyway 来设置和填充数据库:

public void migrate(JdbcTemplate jdbcTemplate) throws Exception {
    jdbcTemplate.execute("create sequence S_CUSTOMER");
    jdbcTemplate.execute("create table CUSTOMER (" +
            "ID BIGINT PRIMARY KEY," +
            "DISPLAY_NAME VARCHAR(3000)," +
            "VERSION BIGINT" +
            ")");
}


public void migrate(JdbcTemplate jdbcTemplate) throws Exception {
    for (int i = 0; i < 10000; i++) {
        jdbcTemplate.update(
                "insert into CUSTOMER (ID, DISPLAY_NAME, VERSION) " + "select nextval('S_CUSTOMER'), ?, ? ",
                "SAP-SE", 0);
    }
}

作为数据库,我使用 PostgreSQL。

当我的应用程序要使用 eclipselink 持久化一个新实体时,我收到一个错误,因为该实体有一个“旧”ID:

Call: INSERT INTO CUSTOMER (ID, DISPLAY_NAME, VERSION) VALUES (?, ?, ?)
bind => [3 parameters bound]
Query: InsertObjectQuery(Customer(id=9959, displayName=Bäckerei Brötchen, version=1)); nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.3.v20160428-59c81c5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "customer_pkey"
Detail: Key (id)=(9959) already exists. 

但是当我手动选择序列的当前值时,我得到的值是“10004”。那么为什么eclipselink会返回一个已经使用过的序列值呢?与休眠相同的东西也可以正常工作。

【问题讨论】:

  • 未指定您的序列分配,EclipseLink 默认为 50。尝试在 SequenceGenerator 中设置 allocationSize=1
  • 在 allocationSize=1 的情况下,序列会正确递增。但这是否意味着 ORM 将每个新的序列号都用于数据库?我认为 allocationSize 旨在通过获取多个序列号来优化性能。
  • 是的,它需要与您为数据库中的序列配置的分配大小相匹配。如果它们关闭,您将获得重复或浪费的号码。 1 表示提供者每次需要数字时都必须进入序列,而 50 表示它可以在增加序列对象时使用前 50 个数字。
  • 对。我的问题是,使用 flyway eclipselink 创建的分配大小为 50 和 10000 个初始条目从 9051 开始分配,这已经被使用了!
  • 这似乎意味着您没有设置分配大小以匹配序列大小。序列中的下一个值应该比任何其他过程使用的最后一个值多 50 个数字,包括 flyway。即,如果最后使用的数字是 10000,那么下一次调用 nextval 应该返回 10050,从而允许 EclipseLink 在需要获取更多数字之前使用 10001-10050。仅在 JPA 中设置分配大小不足以进行预分配,您需要在底层序列对象中进行设置。

标签: hibernate jpa eclipselink spring-data-jpa


【解决方案1】:

我已经与 DB 序列中定义的 allocationSize 相同,但仍然偶尔会得到旧的序列值。

【讨论】:

    【解决方案2】:

    虽然这是一个老问题,但最近我也遇到了同样的问题。

    当您在数据库中创建序列时,allocationSize(默认为 50)应该与子句INCREMENT(默认为 1)相同。 因此,如果你想要一个序列,它会增加 100,你应该这样写:

    CREATE SEQUENCE my_seq_id
      INCREMENT 100
      MINVALUE 1
      MAXVALUE 9223372036854775807
      START 1;
    

    JPA 实体应该是这样的:

    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq_id")
    @SequenceGenerator(name = "my_seq_id", sequenceName = "my_seq_id", allocationSize = 100)
    private Long id;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-21
      • 1970-01-01
      • 1970-01-01
      • 2011-08-24
      • 1970-01-01
      • 1970-01-01
      • 2016-02-02
      • 2011-09-15
      相关资源
      最近更新 更多