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
太多了。 这也只能帮助你在一个会话中有将近50
logging,这些logging不会被保留下来,而且会被持续使用这个特定的会话和转换。
所以在使用SequenceGenerator
时候应该总是使用allocationSize=1
。 至于大部分底层数据库,序列总是加1
。
挖掘到hibernate源代码后,下面的值在50个插入后进入Oracle数据库。 所以每次调用INST_PK_SEQ时,都要增加50。
Hibernate 5用于以下策略
@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号码不匹配。
- 使用@Query使用hibernate更新spring数据jpa中的布尔值
- JPA和Hibernate有什么区别?
- 单向和双向关联有什么区别?
- 在JUnit中使用Springtesting服务时如何回滚数据库事务?
- 如何从Hibernate Criteria API获取SQL(* not *用于日志logging)
- JTA,JPA和Plain JDBC在hibernate方面的区别
- 从Spring MVC发送JSON时dynamic忽略Java对象的字段
- Hibernate,iBatis,Java EE或其他Java ORM工具
- 在@Column JPA annontation上设置length属性时会做些什么?