Grails 或 Spring 方法级事务
Grails or Spring Method Level Transaction
我是spring/grails交易的新手,看完后还是不太清楚,所以我把它发在这里,
我有一个服务 class 被注释为 @Transactional
我有一些方法,其中一些被注释为
@Transactional(propagation = Propagation.REQUIRES_NEW)
其中一些不是。
@Transactional
class SomeService {
def findJob() {
MyInstance myInstance = getMeAJob();
if (myInstance) {
doSomeThing(myInstance)
doTask()
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception)
private doSomeThing(MyInstance myInst) {
myObj = MyInstance.lock(myInst.id)
try {
differentObj = doTask(myObj)
myObj.save()
doAnotherThing()
}
} catch (Exception e) {
log("Error in doAnotherTask")
}
}
private doAnotherThing(MyInstace myInst) {
perform some update on myInst
myInstant.save(flush: true)
}
private doTask() {
}
- 假设,我有来自 class 级别的事务 t1 和 t2
来自 doSomething() 的交易- REQUIRES_NEW.
- 将在 t1 中执行的方法 - findJob() 和 doTask()
将在 t2 中执行的方法 - doSomeThing() - 不影响
"t1" 异常情况下(回滚)
哪个用于 doAnotherThing() 方法?因为我是从 doSomething()?
调用它的
当您有 class 范围注解时,任何未注解的方法都会使用这些设置,而注解方法会使用该注解中的设置覆盖 class 级别的设置。
但是请注意,当使用 Spring 的注释支持(使用 @org.springframework.transaction.annotation.Transactional
)注释时,仅支持 public 方法。不会有错误,但注释会被静默忽略。
但是即使你做了 doSomeThing public(通过删除 private
关键字隐式地或通过将它显式地更改为 public
)它也不会做你期望的事情,当你从 findJob
呼叫 doSomeThing
。这是因为 Spring 的注解会在 运行 时触发创建您的 class 的代理。在这种情况下为您的服务注册的 Spring bean 是一个代理实例,它有一个 class 的 "real" 实例作为其委托。所有事务性 public 方法都被代理拦截,starts/joins/etc。事务,然后调用您的服务方法。一旦您成为 "underneath" 服务实例中的代理,所有方法调用都是直接的,任何注释设置都无效。要使其正常工作,您需要调用 Spring bean 上的方法并通过代理启动新事务。
要避免此代理问题,请改用 Grails @grails.transaction.Transactional
注释。它支持与 Spring 注释相同的事务功能,但不是创建代理,而是 AST 转换重写您的方法以将它们包装在事务中。这使得可以像您正在做的那样进行直接方法调用,并在注释属性定义的其他事务语义下创建新事务或运行。
我 a talk 前一阵子在 Grails 中使用事务可能会有所启发。
我是spring/grails交易的新手,看完后还是不太清楚,所以我把它发在这里,
我有一个服务 class 被注释为 @Transactional 我有一些方法,其中一些被注释为
@Transactional(propagation = Propagation.REQUIRES_NEW)
其中一些不是。
@Transactional
class SomeService {
def findJob() {
MyInstance myInstance = getMeAJob();
if (myInstance) {
doSomeThing(myInstance)
doTask()
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception)
private doSomeThing(MyInstance myInst) {
myObj = MyInstance.lock(myInst.id)
try {
differentObj = doTask(myObj)
myObj.save()
doAnotherThing()
}
} catch (Exception e) {
log("Error in doAnotherTask")
}
}
private doAnotherThing(MyInstace myInst) {
perform some update on myInst
myInstant.save(flush: true)
}
private doTask() {
}
- 假设,我有来自 class 级别的事务 t1 和 t2 来自 doSomething() 的交易- REQUIRES_NEW.
- 将在 t1 中执行的方法 - findJob() 和 doTask()
将在 t2 中执行的方法 - doSomeThing() - 不影响 "t1" 异常情况下(回滚)
哪个用于 doAnotherThing() 方法?因为我是从 doSomething()?
调用它的
当您有 class 范围注解时,任何未注解的方法都会使用这些设置,而注解方法会使用该注解中的设置覆盖 class 级别的设置。
但是请注意,当使用 Spring 的注释支持(使用 @org.springframework.transaction.annotation.Transactional
)注释时,仅支持 public 方法。不会有错误,但注释会被静默忽略。
但是即使你做了 doSomeThing public(通过删除 private
关键字隐式地或通过将它显式地更改为 public
)它也不会做你期望的事情,当你从 findJob
呼叫 doSomeThing
。这是因为 Spring 的注解会在 运行 时触发创建您的 class 的代理。在这种情况下为您的服务注册的 Spring bean 是一个代理实例,它有一个 class 的 "real" 实例作为其委托。所有事务性 public 方法都被代理拦截,starts/joins/etc。事务,然后调用您的服务方法。一旦您成为 "underneath" 服务实例中的代理,所有方法调用都是直接的,任何注释设置都无效。要使其正常工作,您需要调用 Spring bean 上的方法并通过代理启动新事务。
要避免此代理问题,请改用 Grails @grails.transaction.Transactional
注释。它支持与 Spring 注释相同的事务功能,但不是创建代理,而是 AST 转换重写您的方法以将它们包装在事务中。这使得可以像您正在做的那样进行直接方法调用,并在注释属性定义的其他事务语义下创建新事务或运行。
我 a talk 前一阵子在 Grails 中使用事务可能会有所启发。