来自PostgreSQL序列的nextVal多次在Hibernate提取序列中

时间:2014-05-26 08:10:58

标签: java sql hibernate postgresql

对于业务逻辑,我们需要使用直接在数据库中定义的序列中的下一个值更新记录,而不是在Hibernate中更新(因为并不总是应用于插入/更新)

为此目的,我们在PostgreSQL中定义了一个序列,DDL是:

CREATE SEQUENCE public.facturaproveedor_numeracionperiodofiscal_seq
INCREMENT 1 MINVALUE 1
MAXVALUE 9223372036854775807 START 1
CACHE 1;

然后在DAO中,当某些条件成立时,我们通过以下方式获得nextVal:

Query query = sesion.createSQLQuery("SELECT nextval('facturaproveedor_numeracionperiodofiscal_seq')");
Long siguiente = ((BigInteger) query.uniqueResult()).longValue();

但是,所签署的值不是连续的。查看Hibernate输出日志,我们在同一事务中看到对序列的四次提取:

Hibernate: SELECT nextval('facturaproveedor_numeracionperiodofiscal_seq') as num
Hibernate: SELECT nextval('facturaproveedor_numeracionperiodofiscal_seq') as num
Hibernate: SELECT nextval('facturaproveedor_numeracionperiodofiscal_seq') as num
Hibernate: SELECT nextval('facturaproveedor_numeracionperiodofiscal_seq') as num

为什么会这样?这是为了捕捉目的吗?有一种方法可以禁用它吗?或者这种解决方法不正确?

1 个答案:

答案 0 :(得分:2)

Hibernate通常不会生成看起来像那样的独立nextval调用,所以如果你的应用程序正在执行多次提取,我不会感到太惊讶。您需要收集更多的跟踪信息才能确定。

我认为你可能会遇到更大的问题。如果您关注跳过值或留下漏洞的序列,那么您使用错误的工具进行工作,您应该在UPDATE的表中使用计数器,可能是UPDATE my_id_generator SET id = id + 1 RETURNING id。此锁定并发事务,并确保如果事务回滚,则撤消更新

相反,序列并行运行,这意味着当事务回滚时不可能回滚序列增量(参见PostgreSQL文档)。因此,它们通常不适用于会计目的,例如发票编号和其他需要无间隙序列的事项。


对于其他没有特定要求的读者,有时只生成一个值:不要手动生成序列值;使用@GeneratedValue注释。

在Hibernate 3.6及更新版本中,您应该在Hibernate属性中设置hibernate.id.new_generator_mappings

假设您正在从PostgreSQL SERIAL列映射生成的密钥,请使用映射:

@Id
@SequenceGenerator(name="mytable_id_seq",sequenceName="mytable_id_seq", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="mytable_id_seq")

如果省略allocationSize,那么Hibernate假定它是50的奇怪默认值,并且无法检查序列实际上是否递增50 ,因此它尝试插入已使用的ID并失败。

Hibernate / JPA无法自动为非id属性创建值。 @GeneratedValue注释仅与@Id一起使用以创建自动编号