pea*_*kit 313 java spring transactional spring-jdbc spring-aop
我想知道当你用方法注释方法时实际发生了@Transactional什么?当然,我知道Spring会将该方法包装在Transaction中.
但是,我有以下疑问:
注意:由于此机制基于代理,因此只会拦截通过代理进入的"外部"方法调用.这意味着'自调用',即目标对象中调用目标对象的其他方法的方法,即使被调用的方法被标记,也不会在运行时导致实际的事务
@Transactional!
资料来源:http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
为什么只有外部方法调用才会在Transaction下而不是自调用方法?
Rob*_*b H 245
这是一个很大的话题.Spring参考文档专门介绍了多个章节.我推荐阅读面向方面编程和事务的方法,因为Spring的声明式事务支持在其基础上使用AOP.
但是在非常高的层次上,Spring为类本身或成员声明@Transactional的类创建代理.代理在运行时几乎不可见.它为Spring提供了一种方法,可以在方法调用到被代理对象之前,之后或周围注入行为.事务管理只是可以挂钩的行为的一个例子.安全检查是另一个.您也可以提供自己的日志,例如日志记录.因此,当您使用@Transactional注释方法时,Spring会动态创建一个代理,该代理实现与您正在注释的类相同的接口.当客户端调用对象时,会拦截调用并通过代理机制注入行为.
顺便说一句,EJB中的事务工作方式类似.
正如您所观察到的那样,代理机制仅在来自某个外部对象的调用时才起作用.当您在对象内进行内部调用时,您实际上是通过绕过代理的" this "引用进行调用.但是,有办法解决这个问题.我在这个论坛帖子中解释了一种方法,其中我使用BeanFactoryPostProcessor在运行时将代理实例注入"自引用"类.我将此引用保存为名为" me " 的成员变量.然后,如果我需要进行需要更改线程事务状态的内部调用,我通过代理指示调用(例如" me.someMethod() ".)论坛帖子更详细地解释.请注意,BeanFactoryPostProcessor代码现在会有所不同,因为它是在Spring 1.x时间帧中写回来的.但希望它能给你一个想法.我有一个我可能提供的更新版本.
ska*_*man 185
当Spring加载你的bean定义,并且已经配置为查找@Transactional注释时,它将在你的实际bean周围创建这些代理对象.这些代理对象是在运行时自动生成的类的实例.调用方法时这些代理对象的默认行为只是在"目标"bean(即您的bean)上调用相同的方法.
但是,代理也可以提供拦截器,并且当它们存在时,代理将在调用目标bean的方法之前调用这些拦截器.对于使用@Transactional注释的目标bean,Spring将创建一个TransactionInterceptor,并将其传递给生成的代理对象.因此,当您从客户端代码调用该方法时,您将在代理对象上调用该方法,该方法首先调用TransactionInterceptor(它开始一个事务),然后调用目标bean上的方法.调用完成后,TransactionInterceptor将提交/回滚事务.它对客户端代码透明.
至于"外部方法"的事情,如果你的bean调用它自己的一个方法,那么它不会通过代理这样做.请记住,Spring将bean包装在代理中,您的bean不知道它.只有来自bean外部的调用才能通过代理.
这有帮助吗?
pro*_*kpa 38
作为一个视觉人,我喜欢用代理模式的序列图来衡量.如果您不知道如何阅读箭头,我会读到第一个如下:Client执行Proxy.method().
(我被允许在我提到它的起源的情况下张贴照片.作者:Noel Vaes,网站:www.noelvaes.eu)
Ros*_*tha 21
最简单的答案是,在声明@Transactional的任何方法中,事务开始的边界和边界在方法完成时结束.
如果您正在使用JPA调用,则所有提交都在此事务边界中.假设您正在保存entity1,entity2和entity3.现在,在保存entity3时会发生异常,因为enitiy1和entity2属于同一个事务,因此entity1和entity2将与entity3一起回滚.
事务:(entity1.save,entity2.save,entity3.save).任何异常都将导致使用DB回滚所有JPA事务.Spring内部使用JPA事务.
可能已经晚了,但我发现了一些东西,它很好地解释了您与代理相关的问题(只有通过代理传入的“外部”方法调用才会被拦截)。
例如,您有一个如下所示的类
@Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
Run Code Online (Sandbox Code Playgroud)
你有一个方面,看起来像这样:
@Component
@Aspect
public class CrossCuttingConcern {
@Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
public void doCrossCutStuff(){
System.out.println("Doing the cross cutting concern now");
}
}
Run Code Online (Sandbox Code Playgroud)
当你像这样执行它时:
@Service
public class CoreBusinessKickOff {
@Autowired
CoreBusinessSubordinate subordinate;
// getter/setters
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
subordinate.doSomethingSmall(4);
}
Run Code Online (Sandbox Code Playgroud)
}
上面给出的代码调用 kickOff 的结果。
I do something big
Doing the cross cutting concern now
I did something small
Doing the cross cutting concern now
I also do something small but with an int
Run Code Online (Sandbox Code Playgroud)
但是当你将代码更改为
@Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
doSomethingSmall(4);
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
//subordinate.doSomethingSmall(4);
}
Run Code Online (Sandbox Code Playgroud)
您会看到,该方法在内部调用另一个方法,因此它不会被拦截,并且输出如下所示:
I do something big
Doing the cross cutting concern now
I did something small
I also do something small but with an int
Run Code Online (Sandbox Code Playgroud)
你可以通过这样做绕过这个
public void doSomethingBig() {
System.out.println("I did something small");
//doSomethingSmall(4);
((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
}
Run Code Online (Sandbox Code Playgroud)
代码片段取自: https: //www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/ 该页面不再存在。
所有现有答案都是正确的,但我觉得不能只给出这个复杂的话题。
要获得全面、实用的解释,您可能想看看这个Spring @Transactional In-Depth指南,它尽力用大约 4000 个简单的单词来介绍事务管理,并附有大量代码示例。
| 归档时间: |
|
| 查看次数: |
150540 次 |
| 最近记录: |