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的方法,事务不会起作用。
事务不起作用其根本原因就是未通过代理调用,因为事务是在代理中处理的,没通过代理,也就不会有事务的处理。
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的方法,事务不会起作用。
事务不起作用其根本原因就是未通过代理调用,因为事务是在代理中处理的,没通过代理,也就不会有事务的处理。
相关文章推荐
- Java多线程--安全问题
- java正则表达式
- lombok简介及使用方法
- Think in Java 实例变量的初始化
- Think in Java IO流的 字节流部分
- Think in Java 笔记_Chapter12_1_Exception基础_继承和RuntimeException处理1
- Think in Java 笔记_Chapter12_1_Exception基础_异常处理2
- Think in Java 笔记_Chapter12_1_Exception基础_异常处理3_自定义异常以及抛出多个异常的处理
- Think in Java 笔记_Chapter20_1_Annocation基础语法
- Think in Java 笔记_Chapter20_2_Annocation和Junit
- java基础_String类型和char类型、自动类型提升和强制类型转换
- JVM学习04_java中的堆、栈和常量池[看到一篇好文章,加自己想法]
- 10个实用的但偏执的Java编程技术
- Java 里把 InputStream 转换成 String 的几种方法
- Java记录 -35- System类解析
- java 编程思想 阅读笔记(5)
- 《Java编程思想》读后感
- 快速排序的基本思想及Java实现
- java集合框架之List
- 韩顺平 java 第五讲第六讲第七讲 类与对象 成员方法 构造方法