为啥 PostgreSql 的 Hibernate 默认生成器是“SequenceGenerator”,而不是“IdentityGenerator”?
Posted
技术标签:
【中文标题】为啥 PostgreSql 的 Hibernate 默认生成器是“SequenceGenerator”,而不是“IdentityGenerator”?【英文标题】:Why is the Hibernate default generator for PostgreSql "SequenceGenerator", not "IdentityGenerator"?为什么 PostgreSql 的 Hibernate 默认生成器是“SequenceGenerator”,而不是“IdentityGenerator”? 【发布时间】:2012-03-17 05:54:22 【问题描述】:Hibernate 中 Postgresql 的默认标识符生成器是 SequenceGenerator [1]。
即 Hibernate 将在会话提交上执行 INSERT foo (id, ...) VALUES (123, ...)
之前执行 SELECT nextval('hibernate_sequence')
以生成 ID。
然而,PostgreSql 支持自动增量 id 列(参见例如 [2]),并且所有其他支持自动增量的数据库的默认生成器是使用该功能 [3],并执行省略 id 值的插入并查询新 id 的数据库(在会话提交之前,但在会话的事务中)。
我看到最近的一些讨论 [4] 表明,由于 insert-before-session-commit 不匹配,前一种策略总体上更好。
如果 SequenceGenerator 更好(根据 [4]),为什么它不是支持它的数据库的默认值(请参阅 [3])?
如果 IdentityGenerator 更好,为什么 PostgreSql 明确选择 SequenceGenerator 而 Postgres 确实支持前者(根据 [2])?
我试图在 Postgres 方言中查找覆盖默认值的决定的历史记录(请参阅 [1]),但我在 GitHub 中找不到相关的提交。我已经按照代码返回到 SVN 存储库,但是在 r11563 添加 PostgreSQLDialect 文件并带有“maven 迁移”[5] 的无用提交消息的地方变得冷淡。我似乎无法再追溯历史。任何人都可以找到添加此覆盖的提交吗?也许提交消息中有更多信息。
提前致谢。
[1]https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java#L267
[2]PostgreSQL Autoincrement
[3]https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java#L639
[4]http://nhforge.org/blogs/nhibernate/archive/2009/03/20/nhibernate-poid-generators-revealed.aspx
[5]https://source.jboss.org/browse/Hibernate/core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java?focusedRev=14993&fromRev=11563&toRev=14993#r14993
【问题讨论】:
我认为这是因为serial
数据类型只是一个“伪装的序列”。
这并不能解释——所有的自增列都是伪装的序列。
不,不适用于 SQL Server 或 mysql,如果不进行插入,则无法获得下一个值(这是基于序列的解决方案和“自动增量”之间的最大区别)
【参考方案1】:
可能是因为 NHibernate 中的 PG 的 afterInsert 生成器通常被破坏,因为它使用了 npgsql-ADONET 驱动程序不支持的 OracleStyle 输出参数样式,该驱动程序将结果作为查询结果而不是输出参数返回。
SQL: INSERT INTO .... 将 id 返回到 nhout 参数; :nhoutparameter = null;
使用 Oracle 这行得通
command.Execute();
object id = command.Parameter["nhoutparameter"].Value;
Assert.NotNull(id);
在 PG 中没有。应该是
object id = command.ExecuteScalar();
【讨论】:
这对 NHibernate 来说是有意义的。你知道这是否同样适用于 Hibernate? 也许吧。我这里没有环境可以测试。对于 NH,我刚刚获得了源代码并针对 PG 运行了 UnitTests。所有 postInsertGenerator 测试均失败。你可以对 PG 运行的来自 github 的 Hibernatesource 做同样的事情。【参考方案2】:这只是猜测,因为我在 postgres 上找不到好的功能/版本文档,但是...
也许 postgres 方言是在 serial 实现、稳定、广泛使用之前添加的,或者实现方言的开发人员已经意识到这一点。更改方言的默认标识符生成器将是一项重大更改,而且这些更改很糟糕。
【讨论】:
以上是关于为啥 PostgreSql 的 Hibernate 默认生成器是“SequenceGenerator”,而不是“IdentityGenerator”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我在尝试实现 Hibernate 多对多映射时遇到此错误?
Docker/Hibernate/PostgreSQL - 将运行 Hibernate/SpringBoot 应用程序的容器与 postgreSQL 容器不工作连接
long 类型的错误值:- Postgresql、Hibernate、Spring
使用 Hibernate 注释映射 PostgreSQL 串行类型