【问题标题】:Why does Hibernate execute select currval in persist occasionally?为什么Hibernate偶尔会在persist中执行select currval?
【发布时间】:2020-03-02 11:52:03
【问题描述】:

Hibernate 在持久化操作期间有时会随机执行查询:

select currval('MY_TABLE_NAME_id_seq');

实体:

@Entity
@Table(name = "MY_TABLE_NAME")
public class MyEntity {

   @Id
   @Column(name = "ID", unique = true, nullable = false)
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   private Long id;

}

代码:

@Transactional
public void persistMyEntity(String name) {
   MyEntity entity= new MyEntity (name);
   sessionFactory.getCurrentSession().persist(entity);
}

生成的sql:

insert into MY_TABLE_NAME(name) values ('xyz');

select currval('MY_TABLE_NAME_id_seq');

但通常select currval 不会被执行。对此有什么解释吗?

顺便说一句,我的问题与this 非常相似,但问题中的解决方案对我不起作用。

注意:

My_TABLE_NAME ddl sql:

CREATE TABLE my_table_name (
   id bigserial NOT NULL,
   name character varying(256) NOT NULL,
   CONSTRAINT my_table_name_id PRIMARY KEY (id)
);

休眠属性:

Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
hibernateProperties.put("hibernate.hbm2ddl.auto", "none");
hibernateProperties.put("hibernate.connection.release_mode", "auto");
hibernateProperties.put("hibernate.archive.autodetection", ARCHIVE_AUTODETECTION);
hibernateProperties.put("hibernate.format_sql", true);
hibernateProperties.put("hibernate.use_sql_comments", true);
hibernateProperties.put("hibernate.generate_statistics", false);
hibernateProperties.put("hibernate.jdbc.use_scrollable_resultset", true);
hibernateProperties.put("hibernate.jdbc.use_streams_for_binary", true);
hibernateProperties.put("hibernate.jdbc.batch_size", 20);
hibernateProperties.put("hibernate.order_inserts", true);
hibernateProperties.put("hibernate.order_updates", true);
hibernateProperties.put("hibernate.jdbc.batch_versioned_data ", true);
hibernateProperties.put("hibernate.cache.region_prefix", "hibernate.cache");
hibernateProperties.put("hibernate.cache.use_query_cache", false);
hibernateProperties.put("hibernate.cache.use_second_level_cache", false);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
  • PostgreSQL 版本:11.5。
  • hibernate.dialect:org.hibernate.dialect.PostgreSQL9Dialect
  • 休眠版本:5.4.5.Final
  • PostgreSQL JDBC 驱动程序:postgresql-9.4

【问题讨论】:

  • 能否提供hibernate.cfg.xml 设置?你用的是什么休眠版本?
  • @SternK 我添加了。
  • 能否请您也显示您的表MY_TABLE_NAMEddl sql。你用的是什么版本的 PostgreSQL JDBC Driver?
  • 你为hibernate.hbm2ddl.auto的属性使用什么值?
  • @SternK 我还添加了您想要的其他信息。

标签: hibernate jpa jdbc-postgres


【解决方案1】:

根据休眠documentation

2.6.10。使用 IDENTITY 列

为了实现基于 IDENTITY 列的标识符值生成,Hibernate 使用其org.hibernate.id.IdentityGenerator id 生成器,该生成器期望标识符由 INSERT 生成到表中。 IdentityGenerator 了解可以检索 INSERT 生成的值的 3 种不同方式:

  1. 如果 Hibernate 认为 JDBC 环境支持 java.sql.Statement#getGeneratedKeys,那么该方法将用于提取 IDENTITY 生成的密钥。
  2. 否则,如果Dialect#supportsInsertSelectIdentity 报告为真,Hibernate 将使用方言特定的 INSERT+SELECT 语句语法。
  3. 否则,Hibernate 将期望数据库支持某种形式,通过 Dialect#getIdentitySelectString 指示的单独 SQL 命令请求最近插入的 IDENTITY 值

您可以通过以下方式明确指定java.sql.Statement#getGeneratedKeys

<property name="hibernate.jdbc.use_get_generated_keys">true</property>

你不这样做,所以,hibernate 以某种方式将其值视为false。然后休眠检查dialect.getIdentityColumnSupport().supportsInsertSelectIdentity() 的值。你的情况是false。然后通过最后一种方式休眠。请参阅PostgreSQL81IdentityColumnSupport 类的实现。 getIdentitySelectString 方法生成的 sql 与您抱怨的完全相同。

【讨论】:

  • 感谢您的回答。但据我了解,休眠文档hibernate.jdbc.use_get_generated_keys 默认为true。我还观察到通常 hibernate 在不生成 select currval sql 的情况下获取 id。但是很少生成select currval sql。那么我们可以说这是JDBC驱动程序或Hibernate的一种错误吗?这是一个已知问题吗?为什么会发生这种情况你知道吗?
  • 我没有从休眠文档中看到hibernate.jdbc.use_get_generated_keys 默认为true。我看到By default, it tries to detect the driver capabilities from connection metadata.。我试图通过完全使用您的 jdbc 驱动程序版本来重现您的问题,但没有成功。也许它与您的应用程序运行的环境有某种关系。
猜你喜欢
  • 2013-03-08
  • 2016-08-07
  • 2014-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多