java Hibernate、@SequenceGenerator和allocationSize

vmjh9lq9  于 2023-04-28  发布在  Java
关注(0)|答案(6)|浏览(102)

我们都知道Hibernate在使用@SequenceGenerator时的默认行为-它将真实的数据库序列增加1,将此值乘以50(默认值allocationSize)-然后使用此值作为实体ID。
这是不正确的行为,与specification冲突,其内容为:
allocationSize -(可选)从序列中分配序列号时要增加的量。
要明确的是:我不关心生成的ID之间的差距。
我关心的是与底层数据库序列不一致的ID。例如:任何其他应用(即,使用普通JDBC)可能想要在从sequence获得的ID下插入新行-但是所有这些值可能已经被Hibernate使用了!疯狂
有人知道这个问题的解决方案吗(不设置allocationSize=1,从而降低性能)?

编辑:

把事情说清楚。如果最后插入的记录具有ID = 1,则HB同时将值51, 52, 53...用于其新实体BUT:序列在数据库中的值将被设置为2。这在其他应用程序使用该序列时很容易导致错误。
另一方面:规范说(在我的理解中)数据库序列应该设置为51,同时HB应该使用范围为2, 3 ... 50的值

更新:

正如Steve Ebersole在下面提到的:我所描述的行为(对许多人来说也是最直观的)可以通过设置hibernate.id.new_generator_mappings=true来启用。
感谢你们所有人。

更新二:

对于未来的读者,你可以在下面找到一个工作示例。

@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>
ee7vknir

ee7vknir1#

我要说清楚。..你所描述的并不 * 以任何方式与规范冲突。规范讨论的是Hibernate分配给实体的值,而不是实际存储在数据库序列中的值。
但是,有一个选项可以获得您正在寻找的行为。首先看看我对Is there a way to dynamically choose a @GeneratedValue strategy using JPA annotations and Hibernate?的回复,这将给予你一些基础知识。只要您设置为使用SequenceStyleGenerator,Hibernate将使用SequenceStyleGenerator中的“池化优化器”解释allocationSize。“池化优化器”用于在创建序列时允许“增量”选项的数据库(并非所有支持序列的数据库都支持增量)。不管怎样,请阅读这里的各种优化策略。

mum43rcc

mum43rcc2#

allocationSize=1是在获得查询之前的一个微优化,Hibernate试图在allocationSize的范围内赋值,因此试图避免查询数据库的序列。但如果将其设置为1,则每次都会执行此查询。这几乎没有任何区别,因为如果你的数据库被其他应用程序访问,那么如果同一个ID同时被另一个应用程序使用,就会产生问题。
下一代Sequence Id基于allocationSize。
默认情况下,它被保存为50,这太多了。如果你在一个会话中有大约50的记录,这些记录没有被持久化,而这些记录将使用这个特定的会话和事务来持久化,那么它也会有帮助。
因此,在使用SequenceGenerator时,应始终使用allocationSize=1。对于大多数底层数据库,序列总是以1递增。

8cdiaqws

8cdiaqws3#

我将检查DDL中模式中的序列。JPA实现只负责创建具有正确分配大小的序列。因此,如果分配大小为50,那么序列的DDL中必须有50的增量。
这种情况通常可能发生在创建分配大小为1的序列,然后将其配置为分配大小50(或默认值),但序列DDL不更新。

dba5bblo

dba5bblo4#

Steve Ebersole和其他成员
你能解释一下为什么一个id有一个更大的差距(默认为50)?使用Hibernate 4。2.15并在org中找到以下代码。hibernate.id.优化工厂卡斯.

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生成了以下序列id:
1、2、3、4、19、250、251、252、400、550、750、751、752、850、1100、1150。
我知道你已经说过它与规范没有冲突,但我相信这对大多数开发者来说是非常意想不到的情况。
任何人的意见都会很有帮助。
日焕
更新:ne1410s:谢谢编辑。
好的,我会的。这是我的第一篇文章,不知道如何使用它。
现在,我更好地理解了为什么maxLo用于两个目的:由于hibernate调用DB序列一次,在Java级别中不断增加id,并将其保存到DB中,因此Java级别id值应考虑在下次调用序列时,在不调用DB序列的情况下发生了多少变化。
例如,sequence id在某个时刻是1,hibernate输入了5、6、7、8、9(allocationSize = 5)。下一次,当我们得到下一个序列号时,DB返回2,但hibernate需要使用10,11,12。..所以,这就是为什么“hi = lastSourceValue.copy().multiplyBy(maxLo+1)”用于从DB序列返回的2中获取下一个id 10。似乎唯一令人烦恼的事情是在频繁的服务器重新启动,这是我的问题与更大的差距。
因此,当我们使用SEQUENCE ID时,表中插入的id将与DB中的SEQUENCE编号不匹配。

col17t5w

col17t5w5#

在深入研究了hibernate源代码和Below配置之后,在50次插入之后,将转到Oracle数据库获取下一个值。所以每次调用INST_PK_SEQ时,都要增加50。
Hibernate 5用于以下策略
查看下面的 www.example.com

@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;
hfyxw5xn

hfyxw5xn6#

我在Hibernate 5中也遇到了这个问题:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
@SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE)
private Long titId;

下面是这样的警告:
发现使用了已弃用的[org.hibernate.id.SequenceHiLoGenerator]基于序列的id生成器;使用org. hibernate。id.enhanced.SequenceStyleGenerator改为。请参阅Hibernate Domain Model Mapping Guide了解详细信息。
然后将我的代码改为SequenceStyleGenerator:

@Id
@GenericGenerator(name="cmrSeq", strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name = "sequence_name", value = "SEQUENCE")}
)
@GeneratedValue(generator = "sequence_name")
private Long titId;

这解决了我的两个问题:
1.已修复不推荐使用的警告
1.现在,按照oracle序列生成id。

相关问题