事务控制器操作中的 Grails 事务服务调用

grails transactional service calls inside transactional controller action

这两个控制器动作有什么区别:

  @Transactional
    def save(SomeDomain someDomain) {
        someDomain.someProperty = firstService.createAndSaveSomething(params)    //transactional
        someDomain.anotherProperty = secondService.createAndSaveSomething(params) //transactional
        someDomain.save(flush: true)
    }

    def save(SomeDomain someDomain) {
        combinedService.createAndSave(someDomain, params) //transactional, encapsulating first and second service calls
    }

我的目的是在事务失败时回滚整个 save() 操作。但是不知道该用哪个。

您可以使用这两种方法。

firstServicesecondService 抛出异常时,您的清单 #1 将回滚控制器事务。

在清单 #2 中(我希望 combinedServicecreateAndSave 方法用 @Transactional 注释)如果 createAndSave 抛出异常,将回滚事务。使用这种方法的一大优点是这种服务方法理论上可以在其他控制器中重用。

关于 @Transactional 的一个关键点是有两个单独的概念需要考虑,每个概念都有自己的范围和生命周期:

  1. 持久化上下文
  2. 数据库事务

事务注释本身定义了单个数据库事务的范围。数据库事务发生在持久性上下文的范围内。您的代码:

@Transactional
    def save(SomeDomain someDomain) {
        someDomain.someProperty = firstService.createAndSaveSomething(params)    //transactional
        someDomain.anotherProperty = secondService.createAndSaveSomething(params) //transactional
        someDomain.save(flush: true)
    }

持久性上下文在 JPA EntityManager 中,使用 Hibernate Session 在内部实现(当使用 Hibernate 作为持久性提供程序时)。您的代码:

def save(SomeDomain someDomain) {
        combinedService.createAndSave(someDomain, params) //transactional, encapsulating first and second service calls
    }

注意: 持久性上下文只是一个同步器对象,它跟踪一组有限的 Java 对象的状态并确保这些对象的更改最终被存入数据库。

结论:声明式事务管理机制(@Transactional)非常强大,但很容易被误用或错误配置。

了解它的内部工作原理有助于解决机制根本无法正常工作或以意外方式工作的情况。