使用 Hibernate 注释映射 PostgreSQL 串行类型

Posted

技术标签:

【中文标题】使用 Hibernate 注释映射 PostgreSQL 串行类型【英文标题】:Mapping PostgreSQL serial type with Hibernate annotations 【发布时间】:2011-06-26 04:05:12 【问题描述】:

我正在使用 Hibernate 3.3 和 PostgreSQL 8.x,并希望使用 Hibernate 注释来映射不是主键的自动递增列。

列是否使用 SERIAL 类型或 Postgres 中的序列映射无关紧要,只要它由数据库而不是 Hibernate 自动递增。我尝试了以下映射,但它们总是生成 null orderId。

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

我将不胜感激。

谢谢

【问题讨论】:

你确定是null?你是怎么确定的? 我写了一个集成测试并在调试器中检查了这个字段的值。 @alecswan 请修改选择的答案 - 我相信我的答案更正确,我个人必须不断回到这里来记住如何正确地做到这一点!每次我尝试使用不正确的答案,然后再进一步寻找自己的正确答案! 【参考方案1】:

以下映射应该可以正常工作:

@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;

【讨论】:

在加载对象之前刷新会话不起作用。我注意到 Hibernate 只是在 Postgres 数据库中生成类型为 INTEGER 的 orderid 列。如果类型不是 SERIAL 并且 Hibernate 不会生成任何会更新此列的触发器,我根本看不到这将如何工作。还有其他想法吗?谢谢 @alecswan:已更新。此外,刷新与保存对象的会话有关,而不是与加载对象的会话有关。 在我的例子中,对象是在同一个会话中保存和加载的。添加 columnDefinition = "serial" 解决了问题,谢谢!是否有解决方案,例如使用身份生成器,使此解决方案也适用于其他数据库? @alecswan:据我所知,Hibernate 不支持非 id 属性的生成器。 投票,因为这可用于在非 id 列上生成值。这可能是一个大问题。这使得休眠特定(而不是 JPA)和数据库特定(PostgreSQL)的缺点变得容易。就我而言,这不是问题。【参考方案2】:

接受的答案对我不起作用。

尽管如此:

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

【讨论】:

这也是 JPA 不兼容的奖励。 兼容怎么加分? 为我工作,没有columnDefinition = "serial",我更喜欢只在 SQL 生成文件中声明它,使用 flyway(或 liquibase) 等等,OP不是说他的列不是主键吗? @Id 注释在这种情况下是否仍然适用? @Klesun 我一定错过了这个要求 - 哎呀【参考方案3】:

我将它与 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;

【讨论】:

你也可以使用strategy=GenerationType.IDENTITY 没有@Id 是否可以工作? (因为问题是明确的字段不是 id 字段) 这个^是JPA注解版本,谢谢!【参考方案4】:

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

从 db 检查您的序列 id 并执行此 sql 命令。 (不要忘记备份你的数据库以防万一)

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

【讨论】:

【参考方案5】:

我尝试了GenerationTime.INSERTGenerationType.IDENTITY,但都没有阻止null 在更新的saveAll() 调用中插入。

帮助将该字段标记为不可写以进行休眠:

@Column(insertable = false, updatable = false)
private Integer orderId;

(感谢this answer)

【讨论】:

以上是关于使用 Hibernate 注释映射 PostgreSQL 串行类型的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JPA/Hibernate 注释将 MySQL char(n) 列映射到实例变量?

如何使用 hibernate/jpa 注释将一个类映射到不同的表

Spring MVC“org.hibernate.PropertyAccessException”中的休眠注释映射异常

Hibernate 注释或 XML 配置

为啥人们继续使用 xml 映射文件而不是注释? [关闭]

未能延迟初始化角色集合:无法初始化代理 - Hibernate 中的 @ManyToMany 映射注释中没有会话错误? [复制]