繁体   English   中英

Hibernate,@ SequenceGenerator和allocationSize

[英]Hibernate, @SequenceGenerator and allocationSize

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

这是不正确的行为,并与规范冲突说:

allocationSize - (可选)从序列中分配序列号时的增量。

要明确:我不打算生成ID之间的差距。

我关心的是与底层数据库序列不一致的 ID。 例如:任何其他应用程序(例如使用普通JDBC)可能希望在从序列获取的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可以启用我描述的行为(也是最直观的行为)。

谢谢大家。

更新2:
对于未来的读者,您可以在下面找到一个有效的例子。

@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为您的实体分配的值,而不是实际存储在数据库序列中的值。

但是,可以选择获取您正在寻找的行为。 首先看看我的回复是否有办法使用JPA注释和Hibernate动态选择@GeneratedValue策略? 这将为您提供基础知识。 只要您设置为使用SequenceStyleGenerator,Hibernate将使用SequenceStyleGenerator中的“池化优化器”来解释allocationSize “池化优化器”用于允许在序列创建时使用“增量”选项的数据库(并非所有支持序列的数据库都支持增量)。 无论如何,请阅读那里的各种优化策略。

allocationSize=1在获取查询之前它是一个微优化Hibernate尝试在allocationSize的范围内分配值,因此尽量避免查询数据库的序列。 但是如果将其设置为1,则每次都会执行此查询。这几乎没有任何区别,因为如果您的数据库被其他应用程序访问,那么如果另一个应用程序同时使用相同的ID,则会产生问题。

下一代Sequence Id基于allocationSize。

通过defualt它被保持为50太多了。 只有在一个会话中有大约50条记录没有持久存在并且将使用此特定会话和转换持续存在时,它也将有所帮助。

因此,在使用SequenceGenerator时应始终使用allocationSize=1 对于大多数底层数据库,序列总是递增1

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

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。

我知道你已经说它与规范没有冲突,但我相信对于大多数开发者来说这将是非常意想不到的情况。

任何人的意见都会有所帮助。

Jihwan

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

现在,我更好地理解为什么maxLo用于两个目的:由于hibernate一次调用DB序列,继续增加Java级别的id,并将其保存到DB,Java级别id值应该考虑在没有调用的情况下改变了多少下次调用序列时的DB序列。

例如,序列id在某一点为1,而休眠则为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编号不匹配。

在深入了解hibernate源代码之后,在50次插入之后,下面的配置将转到Oracle db以获取下一个值。 因此,每次调用时,使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实现仅负责创建具有正确分配大小的序列。 因此,如果分配大小为50,那么您的序列在其DDL中必须具有50的增量。

这种情况通常可以通过创建具有分配大小1的序列然后配置为分配大小50(或默认值)但序列DDL未更新而发生。

我也在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。 有关详细信息,请参阅“休眠域模型映射指南”。

然后将我的代码更改为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. 已弃用的警告已修复
  2. 现在根据oracle序列生成id。

暂无
暂无

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

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