You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate报错HHH000099:save后detach再执行merge出现断言失败问题

报错根因

你遇到的HHH000099: possible non-threadsafe access to session报错不是真正的多线程访问Session导致的,是你的代码逻辑和Hibernate实体状态管理规则冲突,触发了Hibernate内部的状态校验断言:

    1. 主键生成策略冲突:如果你的Customer实体主键配置的是自动生成策略(比如自增、序列),你手动为Transient状态的实例指定主键值,会打乱Hibernate对实体状态的判断逻辑
    1. SessionFactory使用错误:你将全局重量级的SessionFactory放到try-with-resources块中自动关闭,属于错误用法。SessionFactory应该在应用启动时初始化一次全局复用,程序退出时才关闭,你这种写法会导致Session的上下文绑定状态异常,触发Hibernate误判为非线程安全访问
    1. 状态流转逻辑问题:save()后实体进入Persistent状态,detach()后转为Detached状态,此时调用merge()时,Hibernate会校验实体主键的生成来源,手动指定主键的Detached实体会和一级缓存的历史状态产生冲突,触发断言失败。
修复方案

你可以按照如下顺序调整代码即可解决问题:

  1. 把SessionFactory的初始化移出业务方法的try-with-resources块,全局复用
  2. 若需要手动指定实体主键,将主键生成策略改为assigned(由应用侧指定主键)
  3. 调整后的运行代码如下:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 03:21:02