Hibernate使用PostgreSQL序列不影响序列表
Posted
技术标签:
【中文标题】Hibernate使用PostgreSQL序列不影响序列表【英文标题】:Hibernate use of PostgreSQL sequence does not affect sequence table 【发布时间】: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存放在哪里?
谢谢。
【问题讨论】:
【参考方案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(因为这是对新应用的建议):
-
GenerationType.AUTO -> 被视为 GenerationType.SEQUENCE
GenerationType.SEQUENCE -> 映射到博客中讨论的 org.hibernate.id.enhanced.SequenceStyleGenerator 类
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 并找到表、列或序列名称。
【讨论】:
以上是关于Hibernate使用PostgreSQL序列不影响序列表的主要内容,如果未能解决你的问题,请参考以下文章
使用自动创建表时,Hibernate 不会自动为数据库创建序列
Hibernate 5 ID AUTO 生成类型为 Oracle 作为序列和 MySQL 作为身份
如何使用 JPA 和 Hibernate 映射 PostgreSQL 枚举