您的位置:首页 > 编程语言 > Java开发

Spring 事务

2015-09-17 23:45 295 查看
基于JDK接口代理

jdk代理后生成一个实现了接口的实现类(区别于自己写的实现类)

public final class
WorldServiceProxy extends
Proxy implements
WorldService, SpringProxy,Advised

需要注意的是@Transactional标注的有效位置,只有在有效位置标注了@Transactional,在JdkDynamicAopProxy.invoke()中才能获取到Transaction Advisor来处理事务。否则,要么不会生成代理,要么即使生成了代理,代理也不会真正去管理事务,这两种情况都不会开启事务。
有效标注位置为:
1) 接口上:会为实现类(目标类)里的所有实现自接口的方法开启事务,包括final的。
2) 目标类上:会为实现类(目标类)里的所有实现自接口的方法开启事务,包括final的。。
3) 接口方法上:会为实现类(目标类)里实现自接口的方法且在接口里标注了@Transactional的方法开启事务,包括final的。
4) 目标类方法上:会为标注了@Transactional的且实现自接口的方法开启事务,包括final的。
5) 以上4种情况并集。

特别注意,以上几种情况都只能通过调用代理类才会开启事务,代理类实例是通过容器注入或从容器中获取的。下面几种场景,事务并不起作用:
1) 直接调用目标类的实例,如,
WorldServicews = new WorldServiceImpl();
ws.world1();
通过上面原理阐述,不难知道,虽然world1()标注了@Transactional,但ws并未通过代理调用world1(),也就不能通过Transaction Advisor处理事务。

2) 目标类方法自调用,根据【代码1】,如下方式调用,
ApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");
WorldServicews = (WorldService)ctx.getBean("worldService");
ws.world2();
虽然ws指向的是代理类实例,world1()也加了@Transacional注解,但因为world2()并未加@Transacional注解,world2()也就不具有事务。通过world2()调用world1(),是通过this调用,也就是直接调用的目标类实例,所以也就不能通过代理为world1()开启事务。

Cglib代理

cglib代理后生成一个继承我们自己写的目标类的子类

PublicclassHelloServiceProxyextendsHelloService

有效标注位置为:
1) 目标类上:会为目标类里的所有public非final的实例方法开启事务。
2) 目标类方法上:会为标注了@Transactional的且为public非final的实例方法开启事务。
3) 以上2种情况并集。其他标注位置均无效。

看到这里,大家可能会产生疑问,为什么protected和package可见性的非final实例方法上标注了@Transactional注解,不能开启事务呢?这些方法也是可以在子类中重写的呀?

的确,在java继承体系中,子类能够重写父类中的public或protected或相同包下package可见性的,且非final的实例方法。理论上,也是可以为protected和protected方法如同public一样通过子类中重写的方法开启事务的,实际却不能,这或许是Spring作者基于某些原因对实现做出的取舍吧。

特别注意,以上几种情况,类似JDK接口代理的原理,下面几种场景,事务并不起作用:
1) 直接调用目标类的实例
2) 目标类方法自调用




常见陷阱

@Transactional标注无效的方法


1) JDK接口代理:

除了实现自接口的方法(包括final的),其他方法均无效。

2) Cglib代理:

除了public的非final的实例方法,其他方法均无效。无效的有static的,private,protected,package可见范围的,public final的。

类方法自调用

如前文所述,在目标类内部通过this调用一个标注了@Transactional的方法,事务不会起作用。

事务不起作用其根本原因就是未通过代理调用,因为事务是在代理中处理的,没通过代理,也就不会有事务的处理。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: