grails 如何禁用方法的事务
grails how to disable transactional for a method
我有一个向外部系统转账的服务方法to/from。
它应该首先在我们的系统中创建一个交易(所以我们有一个 transactionId)
然后我们调用外部系统。
如果外部系统出现故障,我们需要回滚交易,然后在我们的支付审计日志中写入一条新记录table,无论调用失败还是成功。
在这种情况下,我不知道如何控制事务。
我了解默认情况下服务是事务性的。
我假设我可以创建 3 种方法(它们现在都是 1 种方法,这不起作用,因为我无法控制提交的内容和回滚的内容)
- createPaymentTransaction()
- sendToPaymentSystem()
- 创建付款记录()
如果 1 失败,我需要回滚 1,仅此而已。
如果 2 失败,我需要回滚 1,但写 3。
如果 1 和 2 有效,我需要写 3。
我不知道如何注释这些,或者如何构造第 4 个请求来管理第 3 个请求。
默认情况下,服务中的所有方法都是事务性的,但您可以使用注释逐个方法地更改行为,例如
import grails.transaction.*
// By default all methods are transactional
@Transactional
class MyService {
@NotTransactional
def notTransactional() {
}
// inherits the class-level default
def transactional() {
}
}
有关交易注释的更多详细信息,请参阅 Grails manual。
如果您需要在比按方法更细粒度的级别管理事务,您可以使用 withTransaction domain class method to manage transactions programatically。
我会选择这样的东西:
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()
}
}
}
通过在 class 级别注释,我们为所有方法设置默认值,但可以根据需要进行自定义,例如createPaymentMethod
.
那么调用 method4
将加入一个现有事务,或者在必要时启动一个新事务。如果 createPaymentTransaction
或 sendToPaymentSystem
中出现问题,那么事务将被回滚,但是对 createPaymentRecord
的调用将会发生,因为它在 finally
块中,并且它将运行 在单独的事务中,因此它不受主事务中回滚的影响,并且那里的故障不会影响主事务。
如果您不能使用新的 grails.transaction.Transactional
注释,请使用标准的 Spring org.springframework.transaction.annotation.Transactional
注释,但您需要做一点小改动。 Grails 注释的动机之一是提供与 Spring 注释相同的功能,但避免从服务中调用注释方法的问题。 Spring 注释在 运行 时触发代理的创建,它拦截所有调用,管理方法的事务性,然后调用服务实例中的真实方法。但是使用当前代码,对 createPaymentRecord
的调用将绕过代理(服务实例只是调用自身)并且不会有新事务。 Grails 注释重写字节码以将每个方法包装在使用适用注释设置(显式或从 class 范围注释推断)的事务模板中,因此它在内部和外部都能正常工作。如果使用 Spring 注释,则需要调用代理上的方法,这只涉及访问此服务的 Spring bean。为 GrailsApplication
作为字段添加依赖注入:
def grailsApplication
然后通过
调用createPaymentRecord
grailsApplication.mainContext.myService.createPaymentRecord()
在 finally
块中。
我有一个向外部系统转账的服务方法to/from。
它应该首先在我们的系统中创建一个交易(所以我们有一个 transactionId) 然后我们调用外部系统。 如果外部系统出现故障,我们需要回滚交易,然后在我们的支付审计日志中写入一条新记录table,无论调用失败还是成功。
在这种情况下,我不知道如何控制事务。
我了解默认情况下服务是事务性的。
我假设我可以创建 3 种方法(它们现在都是 1 种方法,这不起作用,因为我无法控制提交的内容和回滚的内容)
- createPaymentTransaction()
- sendToPaymentSystem()
- 创建付款记录()
如果 1 失败,我需要回滚 1,仅此而已。 如果 2 失败,我需要回滚 1,但写 3。 如果 1 和 2 有效,我需要写 3。
我不知道如何注释这些,或者如何构造第 4 个请求来管理第 3 个请求。
默认情况下,服务中的所有方法都是事务性的,但您可以使用注释逐个方法地更改行为,例如
import grails.transaction.*
// By default all methods are transactional
@Transactional
class MyService {
@NotTransactional
def notTransactional() {
}
// inherits the class-level default
def transactional() {
}
}
有关交易注释的更多详细信息,请参阅 Grails manual。
如果您需要在比按方法更细粒度的级别管理事务,您可以使用 withTransaction domain class method to manage transactions programatically。
我会选择这样的东西:
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()
}
}
}
通过在 class 级别注释,我们为所有方法设置默认值,但可以根据需要进行自定义,例如createPaymentMethod
.
那么调用 method4
将加入一个现有事务,或者在必要时启动一个新事务。如果 createPaymentTransaction
或 sendToPaymentSystem
中出现问题,那么事务将被回滚,但是对 createPaymentRecord
的调用将会发生,因为它在 finally
块中,并且它将运行 在单独的事务中,因此它不受主事务中回滚的影响,并且那里的故障不会影响主事务。
如果您不能使用新的 grails.transaction.Transactional
注释,请使用标准的 Spring org.springframework.transaction.annotation.Transactional
注释,但您需要做一点小改动。 Grails 注释的动机之一是提供与 Spring 注释相同的功能,但避免从服务中调用注释方法的问题。 Spring 注释在 运行 时触发代理的创建,它拦截所有调用,管理方法的事务性,然后调用服务实例中的真实方法。但是使用当前代码,对 createPaymentRecord
的调用将绕过代理(服务实例只是调用自身)并且不会有新事务。 Grails 注释重写字节码以将每个方法包装在使用适用注释设置(显式或从 class 范围注释推断)的事务模板中,因此它在内部和外部都能正常工作。如果使用 Spring 注释,则需要调用代理上的方法,这只涉及访问此服务的 Spring bean。为 GrailsApplication
作为字段添加依赖注入:
def grailsApplication
然后通过
调用createPaymentRecord
grailsApplication.mainContext.myService.createPaymentRecord()
在 finally
块中。