【问题标题】:Hibernate generates negative id values when using a sequenceHibernate 在使用序列时生成负 id 值
【发布时间】:2012-04-09 07:47:09
【问题描述】:

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

@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开始向上)

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

【问题讨论】:

  • 您是否检查了 Oracle 中的当前序列并跟踪休眠输出,如果您看到正确的选择下一个序列查询并且如果您将粘贴复制到 sqlplus 中,您会得到正确/相同/预期的结果?

标签: java hibernate jpa jboss7.x jpa-2.0


【解决方案1】:

新的行为如下:

AllocationSize 是为 Hibernate 保留的主键值范围。 并且 select seq.nextval from dual 将仅在休眠使用此范围的主键后完成。

所以你必须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。

【讨论】:

  • 非常有用的答案,因为这些信息显然不在 Hibernate 文档中。
  • 这对我帮助很大。我无法让@SequenceGenerator 工作,因为我不断收到负值和约束错误。只需添加 allocationSize = 1 即可解决。我正在使用 PostgreSQL。
【解决方案2】:

我刚从 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 会自动启用它们。

【讨论】:

【解决方案3】:

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

为了彻底解决问题,我在@SequenceGenerator 中添加了allocationSize1(我省略了)。

【讨论】:

  • 但是为什么你必须同时添加这两个?除了 allocationSize 更改之外,new_generator_mappings 的哪一部分给出了通过将其设置为 false 来解决的问题?
  • 在设置 allocationSize 后设置为 false 才有效
【解决方案4】:

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

我们没有明确定义allocationSize(因此有50的默认值)。我们让我们的应用程序运行,但删除了数据库并重新创建了它。 Hibernate 拥有他的 id-cache,使用了所有这些,然后与数据库通信以获取新的 id。

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

我们遇到了后续错误,因为我们的实体的 id 定义为数据类型 int 而不是 Integer,当休眠继续计数并到达带有 0 的实体时,它认为它不在数据库尚未创建,尝试创建 INSERT 而不是 UPDATE 并收到密钥验证错误。

我仍然无法解释为什么当遇到这种不一致时,hibernate 决定在-48 启动密钥……但对我们来说,这个错误可以通过在更改数据库中的序列之前简单地关闭应用程序来解决。此外,我们所有的实体现在都使用Integer 而不是int 作为id。

希望这些信息对外面的人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-21
    • 2018-05-21
    • 2013-02-26
    • 2011-01-10
    • 2012-05-13
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    相关资源
    最近更新 更多