Hibernate,@SequenceGenerator和allocationSize

当使用@SequenceGenerator时,我们都知道Hibernate的默认行为 – 它将实际的数据库序列增加1 ,将此值乘以50(默认的allocationSize值),然后将此值用作实体ID。

这是不正确的行为,并与说:

allocationSize – (可选)从序列中分配序列号时要增加的数量。

要清楚:我不打扰生成的ID之间的差距。

我关心与底层数据库序列不一致的 ID。 例如:任何其他应用程序(例如使用普通JDBC)可能需要在从序列获得的ID下插入新行 – 但所有这些值可能已被Hibernate使用! 疯狂。

有人知道这个问题的任何解决scheme(没有设置allocationSize=1 ,从而降低性能)?

编辑:
把事情弄清楚。 如果最后插入的loggingID = 1 ,那么HB为其新实体BUT同时使用值51, 52, 53... :数据库中的序列值将被设置为2 。 当其他应用程序正在使用该序列时,这很容易导致错误。

另一方面:规范说(按照我的理解)数据库序列应该被设置为51 ,同时HB应该使用范围2, 3 ... 50

更新:
正如Steve Ebersole在下面提到的:通过设置hibernate.id.new_generator_mappings=true可以启用我描述的行为(也是最直观的行为)。

谢谢你们。

更新2:
对于未来的读者,下面你可以find一个工作的例子。

 @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ") @SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS") private Long id; } 

persistence.xml中

 <persistence-unit name="testPU"> <properties> <property name="hibernate.id.new_generator_mappings" value="true" /> </properties> </persistence-unit> 

要绝对清楚……你所描述的与规范没有任何冲突。 规范讨论Hibernate分配给实体的值,而不是实际存储在数据库序列中的值。

但是,您可以select要查找的行为。 首先看到我的答复是否有一种方法来dynamicselect使用JPA批注和Hibernate的@GeneratedValue策略? 这会给你的基本知识。 只要您设置为使用SequenceStyleGenerator,Hibernate将使用SequenceStyleGenerator中的“池化优化器”来解释allocationSize 。 “合并优化器”用于允许在序列创build时使用“递增”选项的数据库(不是所有支持序列的数据库都支持增量)。 无论如何,请阅读那里的各种优化策略。

allocationSize=1这是一个微观优化,在获取查询之前,Hibernate试图在allocationSize范围内分配值,所以尽量避免查询数据库的顺序。 但是如果你把它设置为1,这个查询就会被执行。这几乎没有什么区别,因为如果你的数据库被其他应用程序访问,那么如果同一个id被另一个应用程序使用,它将会产生问题。

下一代Sequence Id基于allocationSize。

通过defualt它保持为50太多了。 这也只能帮助你在一个会话中有将近50logging,这些logging不会被保留下来,而且会被持续使用这个特定的会话和转换。

所以在使用SequenceGenerator时候应该总是使用allocationSize=1 。 至于大部分底层数据库,序列总是加1

挖掘到hibernate源代码后,下面的值在50个插入后进入Oracle数据库。 所以每次调用INST_PK_SEQ时,都要增加50。

Hibernate 5用于以下策略

也请查看http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence

 @Id @Column(name = "ID") @GenericGenerator(name = "INST_PK_SEQ", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", parameters = { @org.hibernate.annotations.Parameter( name = "optimizer", value = "pooled-lo"), @org.hibernate.annotations.Parameter( name = "initial_value", value = "1"), @org.hibernate.annotations.Parameter( name = "increment_size", value = "50"), @org.hibernate.annotations.Parameter( name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "INST_PK_SEQ"), } ) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INST_PK_SEQ") private Long id; 

我会检查架构中序列的DDL。 JPA实现只负责创build具有正确分配大小的序列。 因此,如果分配大小是50,那么你的序列在它的DDL中必须增加50。

这种情况通常会发生在创build分配大小为1的序列,然后再configuration为分配大小为50(或默认)的情况下,但序列DDL不会更新。

Steve Ebersole和其他成员,
你会不会解释一个更大的差距(默认为50)的原因? 我使用Hibernate 4.2.15,并在org.hibernate.id.enhanced.OptimizerFactory中find了以下代码。

 if ( lo > maxLo ) { lastSourceValue = callback.getNextValue(); lo = lastSourceValue.eq( 0 ) ? 1 : 0; hi = lastSourceValue.copy().multiplyBy( maxLo+1 ); } value = hi.copy().add( lo++ ); 

每当它碰到if语句的内部时,hi值就会变得更大。 所以,我的ID在频繁的服务器重启testing期间会生成以下序列ID:
1,2,3,4,19,250,251,252,400,550,750,751,752,850,1100,1150。

我知道你已经说过和规范没有冲突,但是我相信这对大多数开发者来说是非常意外的情况。

任何人的意见将是非常有帮助的。

Jihwan

更新:ne1410s:感谢编辑。
cfrick:好的。 我去做。 这是我在这里的第一篇文章,不知道如何使用它。

现在,我更好地理解了为什么maxLo被用于两个目的:由于hibernate调用DB序列一次,保持在Java级别增加id,并将其保存到数据库,Java级id值应该考虑改变多less,而不调用下一次调用序列时的DB序列。

例如,一个点的序列号是1,冬眠号是5,6,7,8,9(分配大小= 5)。 下一次,当我们获得下一个序列号,DB返回2,但hibernate需要使用10,11,12 …所以,这就是为什么“hi = lastSourceValue.copy()。multiplyBy(maxLo + 1)”是用于从DB序列返回的2中获得下一个id 10。 似乎只有在繁忙的服务器重启过程中,这是我的问题与更大的差距。

所以,当我们使用SEQUENCE ID时,表中插入的id将与DB中的SEQUENCE号码不匹配。