Hibernate为PostgreSQL插入生成了两个不同的序列ID

6

我定义了一个带有序列生成主键的实体:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_key_gen")
@SequenceGenerator(name = "id_key_gen", sequenceName = "id_key_seq")
@Column(name = "id", unique = true, nullable = false)
public int getId() {
    return this.id;
}

我正在使用PostgreSQL,这个键被定义为序列。根据PostgreSQL的说法

select last_value from id_key_seq;

返回

1603.

当我执行create()来持久化这个实体的一个实例时,我在日志中看到了以下内容(未关联的内容已编辑):

05 15:15:26.948 org.hibernate.id.enhanced.SequenceStructure [DEBUG] - 获得序列值:1604

05 15:15:26.948 org.hibernate.event.def.AbstractSaveEventListener [DEBUG] - 生成的标识符为:1554,使用策略为:org.hibernate.id.enhanced.SequenceStyleGenerator


后续的SQL插入语句引用了值1554,而不是应该使用的1604(基于从SequenceStructure返回的值)。Hibernate从哪里获得了1554?

在我看来,Hibernate在这里有一个错误——SequenceStructure知道正确的下一个值,但它没有被使用。您有解决此问题的任何想法吗?

FYI:我知道此页面上说要使用GenerationType.AUTO,因为“Hibernate的人完全搞砸了”,但除此之外并没有什么不太有用的陈述。

1个回答

6

看起来如果您使用GenerationType.SEQUENCE,需要指定“增量值”为1,以避免将序列用作Hi/Lo种子。

您发布的问题的第一个答案(有用的答案)解释了您需要在@GeneratedValue注释中指定“allocationSize = 1”。

在较新的Hibernate版本中,您可以在Hibernate属性中设置hibernate.id.new_generator_mappings=true,请参见文档


1
谢谢@araqnid,将allocationSize设置为1确实有效,但我对这种方法不是“好的做法”的评论很好奇。 - Gordon
2
将allocationSize设置为1是一种退化情况,使HiLo样式的生成器像普通序列生成器一样工作。另一方面,这正是您所需要的,因此请使用它。查看Hibernate 3.5中的代码,分配大小用于选择优化器实现,因此现在可以优雅地处理它。 - araqnid
在我看来,Hibernate团队需要重新考虑他们对此的实现;它很令人困惑,而且没有必要。将allocationSize设置为1正是我所需要的,但我想知道在PostgreSQL上,这是否应该成为SEQUENCE的默认值。 - Gordon
1
最好设置 hibernate.id.new_generator_mappings,这样可以使一切变得更加清晰。 - Craig Ringer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接