我正在开发一个现有的应用程序,它使用 Hibernate 和 MySQL 在数据库中存储对象。由于应用程序中的所有对象共享一个用于填充主键 id
列的 id
属性,因此最初的开发人员决定将 id
在抽象父类(super class)中,像这样:
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
列创建的序列。这感觉非常危险和 splinter 。
最佳答案
为了使 Hibernate 与 MySQL 和 PostgreSQL 兼容,我将数据库的 PostgreSQL 版本中的 SERIAL
列更改为 BIGINT
。 Hibernate 使用提到的 hibernate_sequence
为新插入的行生成 id。
这样做的缺点是开发人员在切换 MySQL 和 PostgreSQL 时需要了解以下区别:
- 在 MySQL 上,Hibernate 在表定义中使用自动递增列,从而使每个表的 ID 都是唯一的。
- 在 PostgreSQL 上,Hibernate 使用它的
hibernate_sequence
为所有表生成 id,使 id 在所有表中都是唯一的,并导致表中行的 id 之间存在更大的差距。
此解决方案使我能够在 MySQL 和 PostgreSQL 上使用相同的 Java 代码。只有用于创建/更改表定义的 DDL 脚本在数据库之间有所不同。
关于mysql - 让 Hibernate 尊重 MySQL 和 PostgreSQL 中的序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29492064/