简体   繁体   English

从 PostgreSQL 序列中的 nextVal 在 Hibernate 获取序列中多次

[英]nextVal from PostgreSQL sequence in Hibernate fetch sequence multiple times

For business logic we need to update a record with the next value from a sequence defined directly in database and not in Hibernate (because is not always applied on insert / updates)对于业务逻辑,我们需要使用直接在数据库中而不是在 Hibernate 中定义的序列中的下一个值来更新记录(因为并不总是应用于插入/更新)

For this purpose we have a sequence defined in PostgreSQL witch DDL is:为此,我们在 PostgreSQL 中定义了一个序列,其中 DDL 为:

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

Then in DAO, when some conditions are true, we get the nextVal via:然后在 DAO 中,当某些条件为真时,我们通过以下方式获得 nextVal:

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

But the values asigned aren't consecutive.但是分配的值不是连续的。 Looking the Hibernate output log we see four fetchs to the sequence in the same transaction:查看 Hibernate output 日志,我们看到在同一事务中对序列进行了四个提取:

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

Why is this happening?为什么会这样? Is this for catching purposes?这是为了捕捉目的吗? There is a way to disable this?有办法禁用这个吗? Or this workaround is not correct?或者这种解决方法不正确?

Hibernate won't usually generate standalone nextval calls that look like that, so I won't be too surprised if it's your application doing the multiple fetches. Hibernate通常不会生成看起来像这样的独立nextval调用,因此如果您的应用程序执行多次提取操作,我也不会感到惊讶。 You'll need to collect more tracing information to be sure. 您需要收集更多的跟踪信息以确保。

I think you may have a bigger problem though. 我认为您可能会遇到更大的问题。 If you care about sequences skipping values or leaving holes then you're using the wrong tool for the job, you should be using a counter in a table that you UPDATE , probably UPDATE my_id_generator SET id = id + 1 RETURNING id . 如果您关心序列跳过值或留下漏洞,那么您正在使用错误的工具来完成工作,则应该在UPDATE的表中使用计数器,可能是UPDATE my_id_generator SET id = id + 1 RETURNING id This locks out concurrent transactions and also ensures that if the transaction rolls back, the update is undone . 将锁定并发事务 ,并确保如果事务回滚,则撤消更新

Sequences by contrast operate in parallel, which means that it's impossible to roll back a sequence increment when a transaction rolls back (see the PostgreSQL documentation). 相反,序列并行运行,这意味着在事务回滚时,不可能回滚序列增量(请参见PostgreSQL文档)。 So they're generally not suitable for accounting purposes like invoice numbering and other things where you require a gapless sequence. 因此,它们通常不适合用于会计目的,例如发票编号和您需要无间断序列的其他事物。


For other readers who don't have the specific requirement to only sometimes generate a value: don't generate the sequence values manually; 对于没有特定要求仅有时生成一个值的其他读者:不要手动生成序列值; use a @GeneratedValue annotation. 使用@GeneratedValue批注。

In Hibernate 3.6 and newer, you should set hibernate.id.new_generator_mappings in your Hibernate properties. 在Hibernate 3.6及更高版本中,应在Hibernate属性中设置hibernate.id.new_generator_mappings

Assuming you're mapping a generated key from a PostgreSQL SERIAL column, use the mapping: 假设您要从PostgreSQL SERIAL列映射生成的密钥,请使用以下映射:

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

If you omit the allocationSize then Hibernate assumes it's bizarre default of 50 and fails to check that the sequence actually increments by 50 so it tries to insert already-used IDs and fails. 如果您忽略了allocationSize那么Hibernate会认为它是默认值50并且无法检查序列是否实际递增50,因此它尝试插入已使用的ID并失败。

Hibernate/JPA isn't able to automatically create a value for your non-id-properties. Hibernate / JPA无法自动为您的非id属性创建一个值。 The @GeneratedValue annotation is only used in conjunction with @Id to create auto-numbering @GeneratedValue批注仅与@Id结合使用以创建自动编号

Hibernate caches query results. Hibernate 缓存查询结果。

Notice the "as num", looks like hibernate is altering the SQL as well.注意“as num”,看起来 hibernate 也在改变 SQL。

You should be able to tell Hibernate not to cache results with您应该能够告诉 Hibernate 不要缓存结果

query.setCacheable(false);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM