【发布时间】: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