Hibernate 在使用序列时生成负 id 值

问题描述 投票:0回答:5

我有一个具有以下定义的类:

@Id
@SequenceGenerator(name = "SEQ_ACE_WORKERS_QUEUE_STATS_ID", sequenceName = "SEQ_ACE_WORKERS_QUEUE_STATS_ID", allocationSize = 500)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ACE_WORKERS_QUEUE_STATS_ID")
@Column(name = "ID")
private long Id;

当我们在 Jboss 4.2.3 上运行它时,它运行良好并生成了正确的 ID(从 1000+ 开始)

现在我们迁移到 jboss 7.1.1,它会生成负 ID! (从-498开始向上)

知道为什么会发生这种情况吗?

java hibernate jpa jboss7.x jpa-2.0
5个回答
93
投票

新行为如下:

AllocationSize 是为 Hibernate 保留的主键值范围。 只有在休眠消耗了这个范围的主键之后,才会从 Dual 中选择

seq.nextval

所以你必须

allocationSize
(Hibernate)和序列
increment by
(DB)

上声明相同的值

当明确设置

allocationSize=500
时,例如在甲骨文上

create sequence SEQ_ACE_WORKERS_QUEUE_STATS_ID
       MINVALUE 1 
       MAXVALUE 999999999999999999999999999 
       START WITH 1
       INCREMENT BY 500 
       NOCACHE 
       NOCYCLE;

否则,您会注意到由于主键冲突而从数据库中引发负值或约束错误。

当应用程序服务器重新启动时,您会注意到分配的最新主键与重新启动时选择的“新”序列号之间的“跳转”。

最终评论:默认值为 50。因此,如果您在 Hibernate 端未指定

allocationSize
,则 必须 在 DB 端声明
increment by
50。


38
投票

我刚刚从 JBoss 6.1 迁移到 JBoss 7.1 时遇到了这个问题。

根据 JBoss AS 7.1 JPA 文档 (https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide#JPAReferenceGuide-Persistenceunitproperties),

JBoss 7.1 自动设置多个休眠属性。正在设置的属性之一是

hibernate.id.new_generator_mappings
,它会激活使用不同算法且不向后兼容的新 ID 生成器。在 persistence.xml 文件中将此属性设置为 false 将恢复旧的 ID 生成器行为。

hibernate 4 文档还包含有关新 ID 生成器的信息:http://docs.jboss.org/hibernate/core/4.0/manual/en-US/html_single/#mapping-declaration-id-generator

hibernate 文档明确指出,默认情况下不启用新的 ID 生成器,但是,如上所述,JBoss 7.1 会自动启用它们。


27
投票

在我的

hibernate.id.new_generator_mappings
中将
false
设置为
persistence.xml
只是解决我的问题的第一部分:

为了彻底解决问题,我将

allocationSize
添加到
1
中的
@SequenceGenerator
(我省略了)。


1
投票

我们遇到了类似的错误,但原因(可能)不同:

我们没有显式定义

allocationSize
(因此有默认值
50
)。我们运行了应用程序,但删除了数据库并重新创建了它。 Hibernate 有他的 id 缓存,使用了所有它,然后与数据库通信以获取新的 id。

现在 hibernate-id 缓存至少为 50(对于某些表来说可能要高得多),但是数据库被删除、重建并且现在是空的。所以已经存在一些不一致的地方......但无论出于何种原因,hibernate 然后在 -48 开始下一轮 ids。

我们遇到了后续错误,因为我们的实体具有使用数据类型

int
而不是
Integer
定义的ID,并且当hibernate继续计数并到达具有
0
的实体时,它认为它不在数据库中然而,尝试制作
INSERT
而不是
UPDATE
并得到了关键验证错误。

我仍然无法解释为什么 hibernate 决定在遇到这种不一致时在

-48
处启动键...但对于我们来说,可以通过在更改数据库中的序列之前关闭应用程序来解决该错误。此外,我们所有的实体现在都使用
Integer
而不是
int
作为 ids。

希望这些信息对那里的人有帮助。


0
投票

在您的实体中使用策略序列

@GeneratedValue(strategy = GenerationType.SEQUENCE)

并在数据库中创建序列,增量为50,例如:

create sequence <sequence> increment by 50;

© www.soinside.com 2019 - 2024. All rights reserved.