简体   繁体   English

grails如何禁用方法的事务

[英]grails how to disable transactional for a method

I have a service method to transfer funds to/from an external system. 我有一种服务方法来转移资金到外部系统。

it should create a transaction in our system first (so we have a transactionId) Then we call the external system. 它应该首先在我们的系统中创建一个事务(所以我们有一个transactionId)然后我们调用外部系统。 If the external system fails, we need to rollback the transaction, then write a new record in our payment audit log table, regardless of if the call failed or worked. 如果外部系统出现故障,我们需要回滚事务,然后在我们的付款审核日志表中写入新记录,无论呼叫是否失败或有效。

I cant figure out how to control the transaction in this case. 在这种情况下,我无法弄清楚如何控制交易。

I understand services are transactional by default. 我理解默认情况下服务是事务性的。

I assume I could create 3 methods (they are all 1 method now, which doesn't work as I have no control over what gets committed and what gets rolled back) 我假设我可以创建3个方法(它们现在都是1个方法,这不起作用,因为我无法控制提交的内容和回滚的内容)

  1. createPaymentTransaction() createPaymentTransaction()
  2. sendToPaymentSystem() sendToPaymentSystem()
  3. createPaymentRecord() createPaymentRecord()

I need to rollback 1 if 1 fails, and do nothing more. 如果1失败,我需要回滚1,并且不做任何其他事情。 I need to rollback 1 if 2 fails, but write 3. I need to write 3 if 1 and 2 works. 如果2失败,我需要回滚1,但是写3.如果1和2工作,我需要写3。

I don't know how to annotate these, or how to structure a 4th request to manage the 3. 我不知道如何注释这些,或如何构建第4个请求来管理3。

I'd go with something like this: 我会用这样的东西:

package com.myapp

import grails.transaction.Transactional

import org.springframework.transaction.annotation.Propagation

@Transactional
class MyService {

    def createPaymentTransaction() {}

    def sendToPaymentSystem() {}

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    def createPaymentRecord() {}

    def method4() {
        try {
            def transactionId = createPaymentTransaction()
            sendToPaymentSystem(transactionId)
        }
        finally {
            createPaymentRecord()
        }
    }
}

By annotating at the class level, we set the defaults for all methods, but can customize as needed, eg for createPaymentMethod . 通过在类级别进行注释,我们为所有方法设置默认值,但可以根据需要进行自定义,例如createPaymentMethod

So what will happen is that calling method4 will join an existing transaction, or start a new one if necessary. 那么将会发生的是调用method4将加入现有事务,或者在必要时启动一个新事务。 If there's a problem in either createPaymentTransaction or sendToPaymentSystem then the transaction will be rolled back, but the call to createPaymentRecord will happen because it's in the finally block, and it will run in a separate transaction so it isn't affected by a rollback in the main transaction, and a failure there doesn't affect the main transaction. 如果在createPaymentTransactionsendToPaymentSystem出现问题,那么事务将被回滚,但是对createPaymentRecord的调用将发生,因为它位于finally块中,并且它将在单独的事务中运行,因此它不会受到回滚的影响。主要交易和失败不会影响主要交易。

If you're not able to use the new grails.transaction.Transactional annotation, use the standard Spring org.springframework.transaction.annotation.Transactional annotation, but you need to make a small change. 如果您无法使用新的grails.transaction.Transactional注释,请使用标准的Spring org.springframework.transaction.annotation.Transactional注释,但您需要进行一些小的更改。 One of the motivations for the Grails annotation is to provide the same functionality as the Spring annotation, but avoid the problems with calling an annotated method from within the service. Grails注释的一个动机是提供与Spring注释相同的功能,但避免在服务中调用带注释的方法的问题。 The Spring annotation triggers creation of a proxy at runtime which intercepts all calls, manages transactionality for the method, and then calls the real method in the service instance. Spring注释在运行时触发创建代理,该代理拦截所有调用,管理方法的事务性,然后调用服务实例中的实际方法。 But with the current code, the call to createPaymentRecord will bypass the proxy (the service instance is just calling itself) and there won't be a new transaction. 但是使用当前代码,对createPaymentRecord的调用将绕过代理(服务实例只是调用自身),并且不会有新的事务。 The Grails annotation rewrites the bytecode to wrap each method in a transaction template which uses the applicable annotation settings (explicit or inferred from a class-scope annotation), so it works correctly internally and externally. Grails注释重写字节码以将每个方法包装在事务模板中,该模板使用适用的注释设置(显式或从类范围注释推断),因此它在内部和外部都能正常工作。 If using the Spring annotation, you need to call the method on the proxy, which just involves accessing the Spring bean for this service. 如果使用Spring注释,则需要在代理上调用该方法,该方法只涉及访问此服务的Spring bean。 Add a dependency injection for the GrailsApplication as a field: GrailsApplication添加依赖注入作为字段:

def grailsApplication

and then call createPaymentRecord via 然后通过调用createPaymentRecord

grailsApplication.mainContext.myService.createPaymentRecord()

in the finally block. finally块中。

By default all methods in a service are transactional, but you can change the behaviour on a method-by-method basis with annotations, eg 默认情况下,服务中的所有方法都是事务性的,但您可以使用注释逐个方法地更改行为,例如

import grails.transaction.*

// By default all methods are transactional
@Transactional
class MyService {

  @NotTransactional
  def notTransactional() {

  }

  // inherits the class-level default
  def transactional() {

  }
}

See the Grails manual for more details about the transaction annotations. 有关事务注释的更多详细信息,请参阅Grails手册

If you need to manage transactions at a more fine-grained level than per-method, you can use the withTransaction domain class method to manage transactions programatically . 如果您需要以比每个方法更精细的级别管理事务,则可以使用withTransaction域类方法以编程方式管理事务

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

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