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

Hibernate事务未启动异常排查:同步事务API问题咨询

问题分析与解决方案:手动事务与Spring声明式事务冲突

你遇到的这个错误,核心原因是同时混用了Spring的声明式事务(@Transactional注解)和Hibernate手动事务管理,两者的事务控制逻辑发生了冲突。

为什么会报错?

  • @Transactional注解的本质是让Spring帮你自动接管事务的全生命周期:从方法开始时自动开启事务,执行完方法逻辑后自动提交(如果没有异常)或者回滚(如果抛出异常)。
  • 但你在方法内部又手动调用了currentSession.beginTransaction()和transaction.commit()——这相当于在Spring已经启动的事务之外,又手动启动并提交了一个事务。当Spring后续尝试提交它自己管理的事务时,发现事务状态已经被手动操作打乱,就会抛出Transaction not successfully started的错误。

为啥功能还能正常实现?

这要归功于你加的@Synchronized注解:它保证了所有请求串行执行,即使事务管理层面有冲突,第一个请求的手动提交已经完成了数据更新,第二个请求等待后拿到的也是更新后的数据,所以功能看起来是正常的,但事务层面的异常是实打实的问题。

修正方案

推荐两种修正方式,优先选第一种:

方案1:保留@Transactional,移除手动事务代码

让Spring全权管理事务,去掉手动开启和提交事务的代码:

@Synchronized
@Transactional(readOnly = false, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
myApi() {
    def currentSession = sessionFactory.currentSession
    String query = """update table set column = :value"""
    Map params = [value: "value"]
    currentSession.doWork(new Work() {
        public void execute(Connection connection) {
            Sql sql = new Sql(connection)
            // 注意:Sql.executeUpdate的参数顺序是先SQL语句,再参数,你之前写反了
            int updateCount = sql.executeUpdate(query, params)
        }
    })
    // 无需手动commit,Spring会自动处理事务提交/回滚
}

这里还要提醒你:你之前的sql.executeUpdate(params, query)参数顺序是错误的,Sql类的executeUpdate方法通常是先传入SQL语句,再传入参数映射,调整后能避免潜在的SQL执行错误。

方案2:移除@Transactional,完全手动管理事务(不推荐)

如果一定要手动控制事务,就去掉@Transactional注解,自己处理事务的开启、提交和回滚:

@Synchronized
myApi() {
    def currentSession = sessionFactory.currentSession
    def transaction = null
    try {
        transaction = currentSession.beginTransaction()
        String query = """update table set column = :value"""
        Map params = [value: "value"]
        currentSession.doWork(new Work() {
            public void execute(Connection connection) {
                Sql sql = new Sql(connection)
                int updateCount = sql.executeUpdate(query, params)
            }
        })
        transaction.commit()
    } catch (Exception e) {
        // 异常时手动回滚事务
        if (transaction != null && transaction.isActive()) {
            transaction.rollback()
        }
        throw e // 抛出异常让上层处理
    }
}

总结

优先选择方案1,利用Spring的声明式事务可以避免手动操作事务带来的各种潜在问题,同时@Synchronized已经保证了请求的串行执行,完全满足你“同一时间仅执行一个请求,后续请求使用更新后的数据”的需求。

内容的提问来源于stack exchange,提问作者Uday Reddy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:12:10