当前位置: 首页 > 知识库问答 >
问题:

grails服务中嵌套事务可能存在死锁

敖涵容
2023-03-14

我有一个事务性grails服务,它正在进行一些(长时间运行的)处理。在处理过程中,我想更新一个“percentComplete”值(最终将用于在前端显示进度条)。显然,这必须立即写入(即不作为当前事务的一部分),否则它毫无价值。

因此,我使用Grails事务处理插件,特别是“withNewTransaction”方法来启动一个新事务,其中百分比完成属性被更新。

我的问题是,第二次使用“updatePercent完成()”方法时,应用程序在尝试退出“with NewTransaction”方法时挂起(大概是在尝试提交事务时)。

笔记:

  • 如果我在主服务方法中注释掉会话刷新,则没有问题(顺便说一句,由于实际应用程序中的性能原因,此刷新以及清除是必需的)
  • 使用 hsql 数据库,没有问题(请参见数据源)。
  • 也使用圣杯执行器插件,但我不认为这本身会导致任何问题(请参阅库服务测试,它也挂起并绕过插件)。

我应该去哪里调试这个问题?也许我可以在grails/hibernate的某个地方设置一些日志级别来定位正在发生的事情?

执行这项工作的线程似乎在试图从套接字读取时被卡住了,请参见下面的堆栈跟踪。JVM本身似乎没有任何真正的死锁。

这是我的服务级别,链接到下面的完整项目:

package withtransactiontest

class LibraryService {

    static transactional = true

    def sessionFactory

    def loadBooks(library) {

        int repeat = 5
        repeat.times {
            updatePercentComplete(library, it * (100 / repeat))

            // Simulate some long running process in order to be able to see percentComplete getting written to DB.
            Thread.sleep(2000)

            // Update some property (within the default transaction)
            library.name += "x"
            library.save()

            // Comment out the following, and the current method will complete successfully.
            def session = sessionFactory?.currentSession
            session?.flush()
        }

        library.percentComplete = 100
        library.save()
    }

    void updatePercentComplete(library, val) {

        println "before new transaction"
        Library.withNewTransaction {

            println "Percent complete: " + val
            library.refresh()
            library.percentComplete = val
            library.save()

            println "after save"

            // Hang here, second time around.
        }

        println "Percent complete transaction committed"
        library.refresh()
    }
}

链接到grails项目和重新创建问题的集成测试用例

“工作器”线程的堆栈跟踪:

共有1个答案

袁晟
2023-03-14

解决方法是引入一个新的域类,Progress,它具有属性percentCompletebelongsToLibrary。这在新(嵌套)事务中更新,而不是Library实例本身。

 类似资料:
  • 问题内容: 当服务中抛出RuntimeException时,我使用Grail的回滚功能将所有服务更新为事务性。在大多数情况下,我都这样做: 无论如何,我想验证这是否确实会回滚事务……这让我开始思考是否在这一点上已经提交了。此外,如果没有,设置flush:true会改变这一点吗?我对Spring / Hibernate如何完成所有这些工作不是很熟悉:) 问题答案: 是的,那样做。 默认情况下,Gra

  • 环境: 我们有一个应用程序部署在 JBoss 4.2.3.GA 服务器中,它使用Hibernate 3.4 和 JTA 1.0。 有一个导入器创建或更新某些实体,然后导入一些数据。由于多种原因,大部分导入是在新事务中完成的,在每个事务中,在外部事务中创建/更新的实体可能会再次更新。 调用序列类似于以下伪代码: 服务1: 服务2: 问题: 现在的问题是,我们最终会遇到一个竞争条件,有几个事务试图锁定

  • 我试图将一长串文件添加到mysql中,并使用带有grails的spring ACL服务来附加权限。因此,在我的控制器中,我有: 我不用担心Files domain对象,它支持大量数据(特别是因为我已经禁用了mysql中的版本控制),问题出在使用aclUtilService的filesService上,

  • 据我所知,当您尝试在提交前一个事务之前开始一个事务时,会发生这种异常。然而,我不明白为什么在我的情况下会有这种例外。 我有一个Web应用程序与以下servlet: 这是我的Compte对象: 这是我的DAO的接口: 这就是它的实施: 另外,这是我的Spring配置: 关联的应用程序。属性文件包含以下行: 最后,我有以下servlet过滤器,从这里开始事务: 这是在网络上映射的。如下所示的xml文件

  • 问题内容: 我正在研究应用数据库架构更新的脚本。我已经使用start transaction / commit设置了所有的SQL更新脚本。我在命令行上将这些脚本传递给psql。 现在,我需要在一个事务中同时应用多个脚本。到目前为止,我想出的唯一解决方案是从原始脚本集中删除启动事务/提交,然后将它们卡在新的启动事务/提交块中。我正在编写perl脚本来即时执行此操作。 实际上,我想要嵌套事务,但是我无

  • 我有一个使用Hibernate/JPA的持久性Spring Boot应用程序。 我正在使用事务来管理我的数据库持久性,并且我正在使用注释来定义应该以事务方式执行的方法。 在持久化时,我有三个主要的事务粒度级别: 要保留的实体批次 要保留的单个实体 保留实体的单一数据库操作 因此,在考虑整个持久性流量时,您可以想象我有三个级别的嵌套事务。 第2层和第3层之间的交互如我所愿透明地工作,因为在没有为事务