【发布时间】:2015-06-12 01:52:14
【问题描述】:
我正在开发一个使用 Hibernate 和 MySQL 在数据库中存储对象的现有应用程序。由于应用程序中的所有对象共享一个id 属性,该属性用于填充主键id 列,因此最初的开发人员决定将id 放在一个抽象超类中,如下所示:
public abstract class BaseModel implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
}
现在,系统中每个继承自BaseModel 的类都获得了id 属性,Hibernate 会将它整齐地存储在数据库中。到目前为止一切顺利。
该项目目前在其 maven 依赖项中使用 Hibernate 4.3.5.Final:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.5.Final</version>
</dependency>
需要更改此应用程序才能在 MySQL 和 PostgreSQL 上运行。
我遇到了一个问题,即 Hibernate 不尊重 PostgreSQL 中的 id/auto increment 列。当我在数据库中手动插入一行时,PostgreSQL 会插入该行并更新序列。之后我启动应用程序时,Hibernate 会尝试插入 id 为“1”的行,从而有效地忽略 PostgreSQL 序列。
据我所知,为了解决这个问题,我必须告诉 Hibernate 使用具有特定数据库序列的序列生成器,如下所示:
public abstract class BaseModel implements Serializable {
@Id
@SequenceGenerator(name="pk_sequence",sequenceName="entity_id_seq", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="pk_sequence")
@Column(name = "ID")
private Long id;
}
这个解决方案有两个问题(按重要性排序):
- 当新版本的应用程序针对现有的 MySQL 数据库运行时,这会破坏一些东西。
- 这需要我将 id 列“下推”到类层次结构中,并显式管理所有类和表的所有序列,结果证明这是一件苦差事。
第一点可以通过@TableGenerator 注释来解决,我现在正在研究它,但它仍然需要我进行大量重构。有没有更好/更智能的方法来告诉 Hibernate 在应用程序启动时初始化和尊重数据库中现有记录的现有序列或 id?
其他研究:
我注意到应用程序创建了一个名为 hibernate_sequence 的序列,并忽略了 PostgreSQL 为 serial id 列创建的序列。这感觉非常危险和破碎。
【问题讨论】:
-
您使用的是什么 Hibernate 版本?在各种版本中,Hibernate 的序列生成似乎发生了一些重大变化,但我没有找到太多关于它的文档。
-
4.3.5.Final,我在问题中添加了该信息,感谢您指出遗漏。
-
我同意你的“危险和破碎”的观点。它还使用 50 的分配大小而不是 PostgreSQL 默认的 1,但这是 JPA 规范的错误。 Hibernate 期望拥有 db,除非它的配置被覆盖,否则它不会与其他人一起玩得很好。
标签: mysql hibernate postgresql