我已将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行)
问题:
有什么不对吗?
休眠是否应该与序列表同步?
如果没有,它在哪里存储最后生成的id?
谢谢。
答案 0 :(得分:31)
我遇到了同样的问题。它与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
更新:我最终选择了allocateSize = 1,事情似乎正如我现在预期的那样。我的应用程序无论如何我都不需要ID块,所以YMMV。
答案 1 :(得分:23)
不要为Postgres序列使用GenerationType.SEQUENCE!
这完全是违反直觉的,但是Hibernate的人完全搞砸了。如果必须重新启动/重建数据库,必须使用GenerationType.AUTO ,否则Hibernate将拆除您的序列。他们允许这些代码进入生产版本几乎是犯罪过失,但是Hibernate团队因为他们对于错误的位置的牛头立场而非常有名(例如,检查他们在LEFT JOIN上的位置)。 p>
答案 2 :(得分:8)
首先,您必须确定您正在使用的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(因为这是对新应用的推荐):
答案 3 :(得分:0)
在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并找到表,列或序列名称。