Hibernate报错HHH000099:save后detach再执行merge出现断言失败问题
报错根因
你遇到的HHH000099: possible non-threadsafe access to session报错不是真正的多线程访问Session导致的,是你的代码逻辑和Hibernate实体状态管理规则冲突,触发了Hibernate内部的状态校验断言:
- 主键生成策略冲突:如果你的
Customer实体主键配置的是自动生成策略(比如自增、序列),你手动为Transient状态的实例指定主键值,会打乱Hibernate对实体状态的判断逻辑
- 主键生成策略冲突:如果你的
- SessionFactory使用错误:你将全局重量级的
SessionFactory放到try-with-resources块中自动关闭,属于错误用法。SessionFactory应该在应用启动时初始化一次全局复用,程序退出时才关闭,你这种写法会导致Session的上下文绑定状态异常,触发Hibernate误判为非线程安全访问
- SessionFactory使用错误:你将全局重量级的
- 状态流转逻辑问题:
save()后实体进入Persistent状态,detach()后转为Detached状态,此时调用merge()时,Hibernate会校验实体主键的生成来源,手动指定主键的Detached实体会和一级缓存的历史状态产生冲突,触发断言失败。
- 状态流转逻辑问题:
修复方案
你可以按照如下顺序调整代码即可解决问题:
- 把
SessionFactory的初始化移出业务方法的try-with-resources块,全局复用 - 若需要手动指定实体主键,将主键生成策略改为
assigned(由应用侧指定主键) - 调整后的运行代码如下:
package lk.mysite.demo.orm; import lk.mysite.demo.orm.entity.Customer; import lk.mysite.demo.orm.util.HibernateUtil; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; public class ContextDemo16 { // 全局复用SessionFactory,启动时初始化一次 private static final SessionFactory sf = HibernateUtil.getSessionFactory(); public static void main(String[] args) { try (Session session = sf.openSession();) { session.beginTransaction(); Customer customer = new Customer(5, "John", "New York"); session.save(customer); session.detach(customer); // merge返回的是持久态实例,需要用新变量接收 Customer mergedCustomer = (Customer) session.merge(customer); session.getTransaction().commit(); } catch (HibernateException e) { e.printStackTrace(); } } }
注意:
merge()方法不会改变传入的 Detached 实例状态,会返回一个新的Persistent状态的实例,后续操作需要使用返回的新实例。
内容的提问来源于stack exchange,提问作者Dhanusha_Perera07
相关产品推荐
相关产品推荐

