使用@Transactional注意的问题
使用@Transactional应注意的问题
@Transactional 基本原理概述
在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
你需要注意的事
- @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能
 - Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。
 - 当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,还是在具体的类上使用 @Transactional 注解比较好。
 - 避免 Spring 的 AOP 的自调用问题:自调用就是方法A内调用本类的另一个加上事务注解的方法B时,方法B中对数据库的操作是不带事务的。
 
Spring AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。
失效原因:

方法one方法two都是public的:
- classA中 ,任意要调用classB的方法,是通过spring代理的方式,那么spring的注解才会生效
 - classA中,方法one 调用同class内的方法two,即this调用,spring注解不会生效(例如@Cachable,@Transaction)
 
解决方法
既然已知原因,那么解决的方法就有了,核心思想就是如何获得动态代理对象,而不是使用this去调用。
方案一:使用AspectJ代理
@Service
public class OrderService {
    private void insert() {
        insertOrder();
    }
@Transactional
    public void insertOrder() {
        //insert log info
        //insertOrder
        //updateAccount
       }
}
insertOrder 尽管有@Transactional 注解,但它被内部方法 insert 调用,事务被忽略,出现异常事务不会发生回滚。
上面的两个问题@Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP 代理造成的。为解决这两个问题,可以使用 AspectJ取代 Spring AOP 代理,但现在有更好的解决方法。
方案二:利用AopContext.currentProxy()方法获得代理
方法的意思是尝试返回当前AOP代理。这种做法非常简洁,但是在默认情况下是不起作用的!因为AopContext中拿不到currentProxy,会报空指针。需要一些额外的配置,但不能对所有的注解拦截都有效,这是因为这些注解不是用的AspectJ代理,如果是@Transactional事务注解的话, 则是生效的,具体细节要翻源码了,这里不推荐使用。
方案三:通过ApplicationContext来获得动态代理对象(推荐)
@Component
public class AsyncService implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    public void async1() {
        System.out.println("1:" + Thread.currentThread().getName());
        // 使用AppicationContext来获得动态代理的bean,然后再执行你调用的方法
        this.applicationContext.getBean(AsyncService.class).async2();
    }
    @Async
    public void async2() {
        System.out.println("2:" + Thread.currentThread().getName());
    }
    // 注入ApplicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
												
											使用@Transactional注意的问题的更多相关文章
- Spring 下默认事务机制中@Transactional 无效的原因
		
Spring中 @Transactional 注解的限制1. 同一个类中, 一个nan-transactional的方法去调用transactional的方法, 事务会失效 If you use (d ...
 - Transactional Replication2:在Subscriber中,主键列是只读的
		
在使用Transactional Replication时,Subscriber 被认为是“Read-Only”的 , All data at the Subscriber is “read-only ...
 - SQL Queries from Transactional Plugin Pipeline
		
Sometimes the LINQ, Query Expressions or Fetch just doesn't give you the ability to quickly query yo ...
 - ORA-14450: attempt to access a transactional temp table already in use
		
在ORACLE数据中修改会话级临时表时,有可能会遇到ORA-14550错误,那么为什么会话级全局临时表会报ORA-14450错误呢,如下所示,我们先从一个小小案例入手: 案例1: SQL> CR ...
 - spring的@Transactional
		
在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务.Spring默认情况下会对运行期例外(RunTimeExcept ...
 - 深入分析@Transactional的用法
		
关键词:事务, 编程式事务,声明式事务.spring 事务管理.AOP事务增强.@Transactional 在分析深入分析@Transactional的使用之前,我们先回顾一下事务的一些基本内容. ...
 - spring注解  @Transactional
		
一.@Transactional所需要的jar包 1.aopalliance.jar 这个包是AOP联盟的API包,里面包含了针对面向切面的接口.(通常Spring等其它具备动态织入功能的框架依赖此 ...
 - Spike Notes on Theory of (Software) Transactional Memory[Doing]
		
Motivation 程序员是否需要在处理一致性问题或者同步时,一定要make hands dirty?能不能专注于应用级原子性,而无需考虑低层操作系统.运行时支持的原子性概念或者语言构造? 软件事务 ...
 - Spring 之注解事务 @Transactional
		
众所周知的ACID属性: 原子性(atomicity).一致性(consistency).隔离性(isolation)以及持久性(durability).我们无法控制一致性.原子性以及持久性,但可以 ...
 - Spring MVC @Transactional注解方式事务失效的解决办法
		
在springMVC类上绑定@Transactional的注解,但是访问数据库时,总是报 can't localtion to current JTA Transactional. 后来发现sprin ...
 
随机推荐
- 基于 CSP 的设计思想和 OOP 设计思想的异同
			
LinkerLin Go语言推崇的CSP编程模型和设计思想,并没有引起很多Go开发者包括Go标准库作者的重视.标准库的很多设计保留了很浓的OOP的味道.本篇Blog想比较下从设计的角度看,CSP和OO ...
 - Win8Metro(C#)数字图像处理--2.17图像木刻效果
			
原文:Win8Metro(C#)数字图像处理--2.17图像木刻效果  [函数名称] 图像木刻效果函数WoodCutProcess(WriteableBitmap src) [函数代码] ///& ...
 - SqlServer 无法为可更新的订阅设置发布服务器登录名 sp_link_publication
			
原文:SqlServer 无法为可更新的订阅设置发布服务器登录名 sp_link_publication 没有截图: 创建可更新订阅,正常创建了发布,在订阅端创建订阅,最后一步提示完成,却出现了警告: ...
 - LINQ查询表达式---------join子句
			
LINQ查询表达式---------join子句 join 子句接受两个源序列作为输入. 每个序列中的元素都必须是可以与另一个序列中的相应属性进行比较的属性,或者包含一个这样的属性. join子句使用 ...
 - 中芯国际在CSTIC上悉数追赶国际先进水平的布局
			
作为中国最大.工艺最先进的晶圆厂,中芯国际的一举一动都会受到大家的关注.在由SEMI主办的2017’中国国际半导体技术大会(CSTIC 2017)上,中芯国际CEO邱慈云博士给我们带来了最新的介绍. ...
 - QT5.1编译后的安装目录问题(硬路径问题)
			
这个是我的编译参数:configure -ltcg -confirm-license -opensource -platform win32-msvc2010 -debug-and-release - ...
 - 京东sdk商家上架接口调用问题总结
			
前言: 最近在做商家发布产品,调用京东sdk,发现问题很多,而且还是在我同事的帮助下完成的,摸索中,菜鸟还请高手门多多提携才好,入正题 首先是引用jd的sdk啦,京东sdk中发布商品需要调用一个 36 ...
 - Qt的QWaitCondition(允许线程在一定条件下唤醒其他线程,这样对不间断上传可能比较适用)
			
对生产者和消费者问题的另一个解决办法是使用QWaitCondition,它允许线程在一定条件下唤醒其他线程.其中wakeOne()函数在条件满足时随机唤醒一个等待线程,而wakeAll()函数则在条件 ...
 - Windows线程生灭(图文并茂)
			
一.线程创建 Windows线程在创建时会首先创建一个线程内核对象,它是一个较小的数据结构,操作系统通过它来管理线程.新线程可以访问进程内核对象的所有句柄.进程中的所有内存及同一进程中其它线程的栈. ...
 - 如何在excel中把汉字转换成拼音
			
---恢复内容开始--- 1.启动Excel 2003(其它版本请仿照操作),打开相应的工作表: 2 2.执行“工具→宏→Visual Basic编辑器”命令(或者直接按“Alt+F11”组合键),进 ...