Java 插入失败后恢复休眠会话状态

Java 插入失败后恢复休眠会话状态,java,hibernate,Java,Hibernate,下面的代码尝试使用Spring+Hibernate将项对象插入数据库。该项具有一个整数id字段作为主键,以及一个受唯一约束的名称列(简化示例)。 我知道该项的id为null(该项是暂时的),但是由于名称字段上的唯一约束,插入仍然可能失败 try { getHibernateTemplate().save(myItem); getHibernateTemplate().flush(); // exception thrown here if the name is not unique }

下面的代码尝试使用Spring+Hibernate将
对象插入数据库。该项具有一个整数id字段作为主键,以及一个受唯一约束的
名称
列(简化示例)。
我知道该项的id为null(该项是暂时的),但是由于名称字段上的唯一约束,插入仍然可能失败

try {
  getHibernateTemplate().save(myItem);
  getHibernateTemplate().flush(); // exception thrown here if the name is not unique
}
catch (DataIntegrityViolationException e) {
  Item itemFromDb = (Item) getHibernateTemplate()
    .find("from Item item where item.name = ?",
           myItem.getName()).get(0);
  //
  // copy some properties from myItem to itemFromDb
  //
  getHibernateTemplate.update (itemFromDb)
}
我需要这段代码在一个事务中循环运行许多项,这就是为什么我试图在插入失败时发出更新

但是,在插入失败后,hibernate会话处于一种奇怪的状态,当我发出select语句从db中获取项目时,会抛出原始的异常

插入失败后,我尝试使用
session.execute()
,但没有效果。有什么想法吗

这是在select失败后我在控制台中看到的。Hibernate在select语句上失败,但仍然打印有关上一个insert语句的信息

WARN  [http-8080-1] hibernate.util.JDBCExceptionReporter (JDBCExceptionReporter.java:77) - SQL Error: 2627, SQLState: 23000
ERROR [http-8080-1] hibernate.util.JDBCExceptionReporter (JDBCExceptionReporter.java:78) - Violation of UNIQUE KEY constraint 'unq_Item_name'. Cannot insert duplicate key in object 'items'.
ERROR [http-8080-1] event.def.AbstractFlushingEventListener (AbstractFlushingEventListener.java:301) - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert: [com.sample.Item]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
另外,请不要告诉我hibernate的saveOrUpdate方法,我知道它的作用

合并-将给定对象的状态复制到具有相同标识符的持久对象上。如果当前没有与会话关联的持久实例,则将加载该实例。返回持久实例。如果给定实例未保存,请保存其副本并将其作为新的持久实例返回。给定实例不会与会话关联。如果关联映射为cascade=“merge”,则此操作将级联到关联实例


一旦抛出数据库异常,Hibernate不保证会话的任何内容。你应该后退。如果我理解波佐的建议,他是说你应该先从名字栏中读出来,以确保插入不会失败。对我来说很有意义。

也许最好在插入/更新之前进行选择?@Bozho,谢谢你的回复。我从中了解到,我需要在保存/更新之前选择对象,出于性能原因,我正试图避免这样做。由于该项是暂时的,merge将尝试保存它,这是我已经做过的(失败),如果它的标识符等于现有的某个项,它将触发更新。您的回答不是很乐观,但不幸的是,我认为它是正确的,特别是关于异常后会话状态的部分。所以我把它标记为这样。很抱歉这么沮丧。复合钥匙能帮你吗?可以包括主键和具有唯一性约束的键。我认为生成的SQL仍然是类似的,但是您可以简化代码,更好地使用二级缓存(不需要查询缓存),等等。
getHibernateTemplate().merge(myItem);