为什么Hibernate偶尔会在persist中执行select currval?

Why does Hibernate execute select currval in persist occasionally?

有时 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_NAMEddlsql:

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

根据hibernate documentation:

2.6.10. Using IDENTITY columns

For implementing identifier value generation based on IDENTITY columns, Hibernate makes use of its org.hibernate.id.IdentityGenerator id generator which expects the identifier to be generated by INSERT into the table. IdentityGenerator understands 3 different ways that the INSERT-generated value might be retrieved:

  1. If Hibernate believes the JDBC environment supports java.sql.Statement#getGeneratedKeys, then that approach will be used for extracting the IDENTITY generated keys.
  2. Otherwise, if Dialect#supportsInsertSelectIdentity reports true, Hibernate will use the Dialect specific INSERT+SELECT statement syntax.
  3. Otherwise, Hibernate will expect that the database supports some form of asking for the most recently inserted IDENTITY value via a separate SQL command as indicated by Dialect#getIdentitySelectString

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

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

你没有这样做,所以,休眠以某种方式将其值视为false。然后休眠检查 dialect.getIdentityColumnSupport().supportsInsertSelectIdentity() 的值。你的情况是false。然后通过最后一种方式进行休眠。参见 PostgreSQL81IdentityColumnSupport class 的执行。 getIdentitySelectString 方法生成与您抱怨的完全相同的 sql。