简体   繁体   English

在事务控制器动作内部执行事务服务调用

[英]grails transactional service calls inside transactional controller action

What's the difference between these two controller actions: 这两个控制器动作之间有什么区别:

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

and

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

My purpose is to rollback the whole save() action if a transaction fails. 我的目的是在事务失败时回退整个save()操作。 But not sure which one shoud I use. 但不确定我应该使用哪一个。

You can use both approaches. 您可以使用两种方法。

Your listing #1 will rollback the controller transaction when firstService or secondService is throwing an exception. firstServicesecondService引发异常时,清单1将回滚控制器事务。

In listing #2 (I expect the createAndSave method of combinedService to be annotated with @Transactional ) will rollback the transaction if createAndSave throws an exception. 在上市#2(我希望createAndSave的方法combinedService与被注解@Transactional )如果将回滚事务createAndSave抛出异常。 The big plus using this approach is that this service method is theoretically reusable in other controllers. 使用此方法的最大好处是,该服务方法在理论上可在其他控制器中重用。

One of the key points about @Transactional is that there are two separate concepts to consider, each with it's own scope and life cycle: @Transactional的关键点之一是要考虑两个单独的概念,每个概念都有自己的范围和生命周期:

  1. the persistence context 持久性环境
  2. the database transaction 数据库事务

The transactional annotation itself defines the scope of a single database transaction. 事务注释本身定义了单个数据库事务的范围。 The database transaction happens inside the scope of a persistence context. 数据库事务在持久性上下文的范围内发生。 Your code: 您的代码:

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

The persistence context is in JPA the EntityManager, implemented internally using an Hibernate Session (when using Hibernate as the persistence provider). 持久性上下文在JPA中是EntityManager,使用Hibernate Session在内部实现(当使用Hibernate作为持久性提供程序时)。 Your code: 您的代码:

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

Note : The persistence context is just a synchronizer object that tracks the state of a limited set of Java objects and makes sure that changes on those objects are eventually persisted back into the database. 注意:持久性上下文只是一个同步器对象,该对象跟踪一组有限的Java对象的状态,并确保最终将这些对象上的更改持久化回到数据库中。

Conclusion : The declarative transaction management mechanism ( @Transactional ) is very powerful, but it can be misused or wrongly configured easily. 结论:声明式事务管理机制( @Transactional )非常强大,但很容易被滥用或错误配置。

Understanding how it works internally is helpful when troubleshooting situations when the mechanism is not at all working or is working in an unexpected way. 在机制无法正常工作或无法正常工作的情况下进行故障排除时,了解其内部工作方式将很有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM