【问题标题】:Hibernate use of PostgreSQL sequence does not affect sequence tableHibernate使用PostgreSQL序列不影响序列表
【发布时间】:2011-05-16 09:09:42
【问题描述】:

我已将 Hibernate 配置为使用 PostgreSQL 序列(通过注释)来为主键 id 列生成值,如下所示:

@Id 
@SequenceGenerator(name="pk_sequence",sequenceName="entity_id_seq")
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="pk_sequence")
@Column(name="id", unique=true, nullable=false)
public int getId() {
    return this.id;
}

我看到这个配置是hibernate已经在持久化时分配了id值> 3000,而对已用序列的查询显示如下:

database=# select last_value from entity_id_seq;
last_value 
------------
     69

(1 行)

问题:
有什么不对吗?
hibernate 是否应该与序列表同步?
如果没有,最后生成的id存放在哪里?

谢谢。

【问题讨论】:

    标签: java hibernate postgresql orm hibernate-mapping


    【解决方案1】:

    我遇到了同样的问题。这与Hibernate的id分配策略有关。当您选择 GenerationType.SEQUENCE 时,Hibernate 使用 HiLo 策略,默认情况下以 50 个块为单位分配 ID。所以你可以像这样显式设置 allocationSize 值:

    @Id 
    @SequenceGenerator(name="pk_sequence",sequenceName="entity_id_seq", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="pk_sequence")
    @Column(name="id", unique=true, nullable=false)
    public int getId() {
        return this.id;
    }
    

    不过,我也听说过将 HiLo 策略与 allocationSize=1 结合使用并不是一个好的做法。当您必须处理数据库管理的序列时,有些人建议使用 GenerationType.AUTO

    更新:我确实最终选择了 allocationSize=1,而且现在似乎一切正常。我的应用程序是这样的,反正我真的不需要 ID 块,所以YMMV

    【讨论】:

    • 谢谢介意的兄弟!我从一开始就注意到了allocationSize,但认为它与调用次数有关,并假设该序列对于任何值都应该是可以的。再次感谢!
    • 出于性能原因(减少到数据库的往返次数),我假设这是由 Hibernate 完成的。如果您在分配大小较低(nextval() 调用较慢)时遇到序列本身的争用,您可以考虑在 PostgreSQL 中为序列本身设置缓存
    • 设置分配大小1不影响jdbc批处理吗?
    【解决方案2】:

    不要对 Postgres 序列使用 GenerationType.SEQUENCE!

    这完全违反直觉,但 Hibernate 的人完全搞砸了。您必须使用 GenerationType.AUTO,否则如果您必须重新启动/重建数据库,Hibernate 将拆除您的序列。他们允许这段代码进入生产构建几乎是犯罪过失,但 Hibernate 团队以他们对完全错误位置的牛头式立场而闻名(例如,查看他们在 LEFT JOIN 上的位置)。

    【讨论】:

    • 好点,马特!但我认为使用 GenerationType.SEQUENCE 是有理由的:如果您有一个从另一个继承了序列 pk 的表继承的表,因此为其共享一个序列,GenerationType.AUTO 将无法为序列 pk 分配正确的值(它将遇到重复值)。
    • 我强烈反对。您必须简单地指定 SequenceGenerator 来使用它,并且(如果您希望与非 Hibernate 应用程序互操作)将 allocationSize 设置为 1。在较新的版本中,您可以改用 hibernate.id.new_generator_mappings=true 来恢复理智;当你写这篇文章时,这可能不是真的,但 allocationSize 选项肯定是。
    • 一些支持您的声明的外部信息会有所帮助,例如错误报告。
    【解决方案3】:

    首先,您必须确定您使用的是哪个版本的 Hibernate。就 hibernate-core 版本而言,3.2 及更高版本引入了对 id 生成器的更一致的支持,尤其是在注释中定义的方面。请参阅http://in.relation.to/Bloggers/New323HibernateIdentifierGenerators 进行讨论。

    Next 3.6 引入了一个设置 ('hibernate.id.new_generator_mappings'),它使该博客中讨论的生成器成为处理 JPA 注释的默认方式。该设置默认为 false,因为 Hibernate 必须保持与旧版本的向后兼容性。如果您想要新的行为(完全推荐),只需将该设置设置为 true。

    GenerationType 的处理方式取决于您使用的版本以及您是否将“hibernate.id.new_generator_mappings”设置为 true。我会假设您使用的是 3.6+(因为任何旧的东西都是旧的)并且确实将“hibernate.id.new_generator_mappings”设置为 true(因为这是对新应用的建议):

    1. GenerationType.AUTO -> 被视为 GenerationType.SEQUENCE
    2. GenerationType.SEQUENCE -> 映射到博客中讨论的 org.hibernate.id.enhanced.SequenceStyleGenerator 类
    3. GenerationType.TABLE -> 映射到博客中讨论的 org.hibernate.id.enhanced.TableGenerator 类

    【讨论】:

      【解决方案4】:

      在 Postgres 中我会这样做:

      @Id 
      @SequenceGenerator(name="pk_sequence",sequenceName="\"entity_id_seq\"")
      @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="\"pk_sequence\"")
      @Column(name="\"id\"", unique=true)
      private int id;
      

      大部分是大写名称,Hibernate 需要传递转义引号才能理解 Postgres 并找到表、列或序列名称。

      【讨论】:

        猜你喜欢
        • 2018-09-14
        • 1970-01-01
        • 2011-01-06
        • 1970-01-01
        • 2015-06-12
        • 1970-01-01
        • 2013-04-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多