【问题标题】:grails how to disable transactional for a methodgrails如何禁用方法的事务性
【发布时间】:2015-02-19 16:18:37
【问题描述】:

我有一种将资金转入/转出外部系统的服务方法。

它应该首先在我们的系统中创建一个事务(所以我们有一个 transactionId) 然后我们调用外部系统。 如果外部系统发生故障,我们需要回滚事务,然后在我们的支付审计日志表中写入一条新记录,无论调用失败还是有效。

我不知道在这种情况下如何控制交易。

我了解服务默认是事务性的。

我假设我可以创建 3 个方法(它们现在都是 1 个方法,这不起作用,因为我无法控制提交的内容和回滚的内容)

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

如果 1 失败,我需要回滚 1,并且什么也不做。 如果 2 失败,我需要回滚 1,但写 3。 如果 1 和 2 有效,我需要写 3。

我不知道如何注释这些,或者如何构造第 4 个请求来管理 3。

【问题讨论】:

    标签: grails transactions


    【解决方案1】:

    我会选择这样的:

    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()
            }
        }
    }
    

    通过在类级别进行注释,我们为所有方法设置默认值,但可以根据需要进行自定义,例如对于createPaymentMethod

    所以会发生什么,调用method4 将加入一个现有事务,或者在必要时启动一个新事务。如果createPaymentTransactionsendToPaymentSystem 有问题,那么事务将被回滚,但对createPaymentRecord 的调用将会发生,因为它在finally 块中,并且它将在单独的事务中运行,所以它不是' 不受主事务回滚的影响,并且那里的失败不会影响主事务。

    如果您无法使用新的 grails.transaction.Transactional 注释,请使用标准 Spring org.springframework.transaction.annotation.Transactional 注释,但您需要进行一些小改动。 Grails 注释的动机之一是提供与 Spring 注释相同的功能,但避免从服务中调用带注释的方法的问题。 Spring 注释在运行时触发创建代理,该代理拦截所有调用,管理方法的事务性,然后调用服务实例中的真实方法。但是使用当前代码,对createPaymentRecord 的调用将绕过代理(服务实例只是在调用自己)并且不会有新事务。 Grails 注释重写字节码以将每个方法包装在事务模板中,该模板使用适用的注释设置(显式或从类范围注释推断),因此它在内部和外部都能正常工作。如果使用 Spring 注解,则需要调用代理上的方法,这只是涉及访问该服务的 Spring bean。为 GrailsApplication 添加依赖注入作为字段:

    def grailsApplication
    

    然后通过电话createPaymentRecord

    grailsApplication.mainContext.myService.createPaymentRecord()
    

    finally 块中。

    【讨论】:

    • 谢谢伯特,这正是我需要的。
    【解决方案2】:

    默认情况下,服务中的所有方法都是事务性的,但您可以使用注释逐个方法更改行为,例如

    import grails.transaction.*
    
    // By default all methods are transactional
    @Transactional
    class MyService {
    
      @NotTransactional
      def notTransactional() {
    
      }
    
      // inherits the class-level default
      def transactional() {
    
      }
    }
    

    有关事务注释的更多详细信息,请参阅Grails manual

    如果您需要在比 per-method 更细粒度的级别管理事务,您可以使用withTransaction 域类方法到manage transactions programatically

    【讨论】:

    • 如果大多数方法都是事务性的,我会使用NotTransactional,并注释那些不是。如果大多数不是,则删除类级别的注释并使用@Transactional 注释事务方法
    • @NotTransactional 是我一直在寻找但在 grails 文档中找不到的东西,我应该尝试一下!然而,传播的东西看起来是一个更好的解决方案
    猜你喜欢
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 2012-12-24
    • 2018-02-07
    • 2011-09-23
    • 2019-11-08
    相关资源
    最近更新 更多