使用Hibernate注释映射PostgreSQL序列类型

28

我正在使用Hibernate 3.3和PostgreSQL 8.x,希望使用Hibernate注解将一个自动递增的列映射到非主键列。

只要数据库自动递增即可,无论是使用Postgres中的SERIAL类型还是sequences进行映射。我尝试了以下映射,但它们始终生成null orderId。

@Column(name = "orderId", insertable = false)
@Generated(GenerationTime.INSERT)
//@GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
private Integer orderId;

我将非常感谢任何对此的帮助。

谢谢


你确定它是“null”吗?你是怎么确定的? - axtavt
我编写了一个集成测试,并在调试器中检查了该字段的值。 - alecswan
@alecswan请重新审查所选答案 - 我相信我的答案更正确,我个人不得不不断地回到这里来记住如何正确地做!每次我尝试使用错误的答案然后寻找自己的正确答案! - pstanton
5个回答

37
以下映射应该可以正常工作:
@Column(name = "orderId")
@Generated(GenerationTime.INSERT)
private Integer orderId;

需要注意的是,对于刚保存的对象而言,生成的值在会话被提交之前不可用。

编辑:需要注意的是,这种映射并不会使Hibernate在模式生成过程中创建一个serial类型的列,因为Hibernate并不知道数据库端的值生成方式的本质。因此,如果您想让Hibernate创建一个具有适当类型的列,您需要明确地指定它:

@Column(name = "orderId", columnDefinition = "serial")
@Generated(GenerationTime.INSERT)
private Integer orderId;

如果您正在使用最近版本的Hibernate(4.3),您可以这样做:

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long orderId;

1
清除会话后加载对象并没有起作用。我注意到Hibernate在Postgres数据库中只生成了类型为INTEGER的orderid列。如果类型不是SERIAL,而Hibernate也没有生成任何触发器来更新此列,我不知道这样是否能够正常工作。你有其他想法吗?谢谢。 - alecswan
1
在我的情况下,对象在同一会话中保存和加载。 添加columnDefinition =“serial”解决了问题,谢谢!是否有解决方案,例如使用Identity生成器,使此解决方案在其他数据库上也能正常工作? - alecswan
1
点赞因为这可以用于在非ID列上生成值。这可能是一个大问题。这使得它易于使用,但缺点是它只适用于Hibernate(而不是JPA)和特定于数据库(PostgreSQL)。在我的情况下,这不是一个问题。 - beginner_
后一种解决方案不起作用。它只插入一次,然后在第二次报告重复键。似乎Hibernate不理解Postgres的SERIAL数据类型。 - emeraldhieu
如果您在Spring Boot中必须使用spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false,那么您的解决方案将无法生效。您必须使用完整选项,例如: @Id @Column(name = "id", columnDefinition = "serial not null") @SequenceGenerator(allocationSize = 1, sequenceName = "opcionais_id_seq", name = "opcionais_id_seq") @GeneratedValue(generator = "opcionais_id_seq", strategy = GenerationType.SEQUENCE) - Rod Lima
显示剩余4条评论

25

对我来说,被接受的答案行不通。

但是这个可以:

@Id
@Column(name = "your_id", columnDefinition = "serial")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer yourId;

这也是JPA不兼容的,这是一个额外的好处。 - pstanton
3
“不兼容”的奖金是什么意思? - hd1
1
对我而言是可行的,没有 columnDefinition = "serial",我更喜欢仅在 SQL 生成文件中声明它,使用 Flyway(或 Liquibase)。 - pdem
1
等等,OP 不是说他的列不是主键吗?在这种情况下,@Id 注释仍然适用吗? - Klesun
@Klesun 我一定错过了那个要求 - 糟糕 - pstanton

5

我正在使用这个工具与postgresql9.1配合使用,8版本也应该可以:

@SequenceGenerator(allocationSize=1, initialValue=1, sequenceName="account_id_seq", name="account_id_seq")
@GeneratedValue(generator="account_id_seq", strategy=GenerationType.SEQUENCE)
@Id
@Column(name="id")
private Integer id;

1
你也可以使用 strategy=GenerationType.IDENTITY - Craig Ringer
2
这个没有@Id会工作吗?(因为问题明确说明该字段不是一个id字段) - Angelo Fuchs
这个 ^ 是 JPA 注释版本,谢谢! - Steve Jones

1
我尝试过使用 GenerationTime.INSERTGenerationType.IDENTITY,但是在更新调用 saveAll() 时,都无法防止插入 null
有帮助的方法是将该字段标记为不可写入的。对于 hibernate 来说是这样的:
@Column(insertable = false, updatable = false)
private Integer orderId;

(向此答案致敬)


0

数据库序列与您的私钥不同步。因此,您需要更新序列索引。

从数据库中检查您的序列ID并执行此SQL命令。(别忘了备份您的数据库以防万一)

SELECT setval('your_primary_key_sequence', (SELECT MAX(your_primary_key) FROM your_table)+1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接