解决Spring AOP 事务 配置 失效原因

2023-05-16

采用AOP配置声明式事务有5种方式,下面只说关于采用TransactionInterceptor事务拦截器的方式,配置程序如下:

transactionManager:


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" /> 

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
	<property name="dataSource" ref="dataSource" />
</bean>  

  

 TransactionInterceptor:

 


<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
	<property name="transactionManager" ref="transactionManager" /> 
	<property name="transactionAttributes"> 
	<props> 
		<prop key="add*">PROPAGATION_REQUIRED</prop> 
		<prop key="del*">PROPAGATION_REQUIRED</prop>
 		<prop key="update*">PROPAGATION_REQUIRED</prop> 
		<prop key="query*">readOnly</prop> 
		<prop key="get*">readOnly</prop> 
		<prop key="find*">readOnly</prop> 
		<prop key="check*">PROPAGATION_REQUIRED</prop> 
		<prop key="operate*">PROPAGATION_REQUIRED</prop> 
		<prop key="batch*">PROPAGATION_REQUIRED</prop> 
		<prop key="deploy*">PROPAGATION_REQUIRED</prop> 
		<prop key="exec*">PROPAGATION_REQUIRED</prop> 
	</props> 
	</property> 
</bean>   

   

自动代理BeanNameAutoProxyCreator:


<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
	<property name="beanNames"> 
		<!-- 所有以BUSImpl命名的Bean-Id都会被事务拦截--> 
		<value>*BUSImpl</value> 
	</property> 
	<property name="interceptorNames"> 
	<list> 
		<value>transactionInterceptor</value>
	</list> 
</property> 
</bean>   

 

业务类例子:

public class UserManageBUSImpl implements IBusiness{ 
	private UserDAO dao; 
	public void addUser(User user) throws Exception{ 
		dao.save(user); 
	} 
} 

 

public class UserDAO implements IDAO{ 
	private JdbcTemplate db;
	public void save(User user) throws Exception{ 
		db.update("insert into User(...) values(...)"); 
		throw new Exception("test exception"); // 这里我们故意抛出异常作为测试 
	} 
} 

   
 然后运行发现记录仍然保存进去了,事务失效;

why?

我们首先应该知道使用事务回滚和提交,归根结底是在JDBC里完成的,这里声明事务拦截器仅是为JDK代理切入点拦截。而做事务提交和回滚是transactionManager完成的事。那么断点跟进拦截器里程序发现:

public Object invoke(final MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be <code>null</code>.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);

		// If the transaction attribute is null, the method is non-transactional.
		final TransactionAttribute txAttr =
				getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);
		final String joinpointIdentification = methodIdentification(invocation.getMethod());

		if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				retVal = invocation.proceed();
			}
			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
......

 
 

completeTransactionAfterThrowing(txInfo, ex);这句话是异常捕获后做的事情,那么再跟进发现:

 

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
	if (txInfo != null && txInfo.hasTransaction()) {
	if (logger.isDebugEnabled()) { 
		logger.debug("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); 
	}
	if (txInfo.transactionAttribute.rollbackOn(ex)) { // 需满足这个条件 
		try { 
			this.transactionManager.rollback(txInfo.getTransactionStatus()); // 这里才完成JDBC事务回滚 
		} catch (RuntimeException ex2) { 
			logger.error("Application exception overridden by rollback exception", ex); 
			throw ex2; 
		} catch (Error err) { 
			logger.error("Application exception overridden by rollback error", ex); throw err; } 
	} 
...... 

  

 看来离真相越来越接近了,txInfo.transactionAttribute是什么呢?查看源码对应到一个接口TransactionAttribute,文档如下:

/**
 * This interface adds a <code>rollbackOn</code> specification to TransactionDefinition.
 * As custom <code>rollbackOn</code> is only possible with AOP, this class resides
 * in the AOP transaction package.
 *
 * @author Rod Johnson
 * @since 16.03.2003
 * @see DefaultTransactionAttribute
 * @see RuleBasedTransactionAttribute
 */
public interface TransactionAttribute extends TransactionDefinition {
	
	/**
	 * Should we roll back on the given exception?
	 * @param ex the exception to evaluate
	 * @return whether to perform a rollback or not
	 */
	boolean rollbackOn(Throwable ex);
	
}

 

 看下RuleBasedTransactionAttribute里实现的接口方法:

 

public boolean rollbackOn(Throwable ex) { 
	if (logger.isDebugEnabled()) {
		logger.debug("Applying rules to determine whether transaction should rollback on " + ex);
	} 
	RollbackRuleAttribute winner = null; 
	int deepest = Integer.MAX_VALUE; 
	if (this.rollbackRules != null) { 
		// 看来这里是要满足自定义回滚规则 
		for (Iterator it = this.rollbackRules.iterator(); it.hasNext();) { 
			RollbackRuleAttribute rule = (RollbackRuleAttribute) it.next(); 
			int depth = rule.getDepth(ex); 
			if (depth >= 0 && depth < deepest) {
 				deepest = depth; winner = rule;
 			}
 		} 
	}
	 if (logger.isDebugEnabled()) {
		 logger.debug("Winning rollback rule is: " + winner); 
	} 
	// User superclass behavior (rollback on unchecked) if no rule matches. 
	if (winner == null) { 
		logger.debug("No relevant rollback rule found: applying superclass default"); 
		return super.rollbackOn(ex); // 如果没有规则,则调用父类方法验证回滚规则 
	}
 	return !(winner instanceof NoRollbackRuleAttribute); } 

   

 其父类方法为:

/** 
* Default behavior is as with EJB: rollback on unchecked exception. 
* Additionally attempt to rollback on Error. 
* Consistent with TransactionTemplate's behavior. 
*/ 
public boolean rollbackOn(Throwable ex) { 
	return (ex instanceof RuntimeException || ex instanceof Error); // 最终是这个原因 
} 

 

原因:

由于业务类里抛出的异常不满足事务拦截器里定义的异常(RuntimeException|Error)事务回滚规则,故事务无效;

解决方案:

1,将业务类的抛出异常改为满足拦截器里的异常规则(不推荐,因为要修改以前所有的代码)

2,(推荐方案)在事务拦截器里声明自定义回滚规则,即this.rollbackRules.iterator()中有你自己申明的异常类,这个方案仅需在spring中配置如下:


<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> 
	<property name="transactionManager" ref="transactionManager" /> 
	<property name="transactionAttributes"> 
	<props> 
		<prop key="add*">PROPAGATION_REQUIRED, -Exception</prop> 
		<prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
		<prop key="update*">PROPAGATION_REQUIRED, -Exception</prop> 
		<prop key="query*">readOnly</prop> 
		<prop key="get*">readOnly</prop> 
		<prop key="find*">readOnly</prop> 
		<prop key="check*">PROPAGATION_REQUIRED, -Exception</prop> 
		<prop key="operate*">PROPAGATION_REQUIRED, -Exception</prop> 
		<prop key="batch*">PROPAGATION_REQUIRED, -Exception</prop> 
		<prop key="deploy*">PROPAGATION_REQUIRED, -Exception</prop> 
		<prop key="exec*">PROPAGATION_REQUIRED, -Exception</prop> 
	</props> 
	</property> 
</bean> 
 

  

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决Spring AOP 事务 配置 失效原因 的相关文章

随机推荐

  • 程序员,最关键的跨越是什么?做到了月薪可能翻上几番~

    黑马程序员视频库 播妞微信号 xff1a boniu236 传智播客旗下互联网资讯 学习资源免费分享平台 作为一名程序员 xff0c 最关键的跨越是什么 xff1f 从普通程序员进阶为熟练开发者 xff0c 从熟练开发者跃升到技术专家或架构
  • VSCODE ssh免密连接远端服务器

    用vscode ssh远程开发时 xff0c 需要输入服务器密码 xff0c 才能正常连接 输入的次数多了就想改进下 既然是通过ssh连接的 xff0c 那么只需要做到ssh免密连接就可以了 具体操作如下 xff1a 1 本地电脑生成秘钥
  • 2022年12月编程语言排行榜,数据来了!

    2022年迎来了最后一个月 xff0c 我们可以看到 xff0c 在这一年中编程语言起起伏伏 xff0c 有的语言始终炙手可热 xff0c 而有的语言却逐渐 没落 日前 xff0c 全球知名TIOBE编程语言社区发布了12月编程语言排行榜
  • 黑马程序员:3分钟带你读懂C/C++学习路线

    随着互联网及互联网 43 深入蓬勃的发展 xff0c 经过40余年的时间洗礼 xff0c C C 43 43 俨然已成为一门贵族语言 xff0c 出色的性能使之成为高级语言中的性能王者 而在今天 xff0c 它又扮演着什么样重要的角色呢 x
  • Python+Matplotlib 制作排序算法的动画

    1 算法的魅力 深刻研究排序算法是入门算法较为好的一种方法 xff0c 现在还记得4年前手动实现常见8种排序算法 xff0c 通过随机生成一些数据 xff0c 逐个校验代码实现的排序过程是否与预期的一致 xff0c 越做越有劲 xff0c
  • 浏览器打不开某些网站是什么原因导致,试试用这些方法来解决

    不少小伙伴使用一些浏览器浏览网页的时候 xff0c 发现打不开某些网站 xff0c 这是什么原因导致的呢 本文讲汇总几个常见的原因 xff0c 我们可以通过以下几个原因排查 xff0c 并且使用下文的解决方法可以试试能否打开网站 打不开网站
  • Android设备的电池续航时间优化(Optimizing Battery Life)——(一)监听电池电量和电池的充电状态...

    当你想通过减少后台更新服务的更新频率来降低程序对电池的影响时 xff0c 检查电池当前的电量和充电状态将是一个比较好的起点 程序更新对电池造成的影响将取决于当前电池电量和充电状态 xff0c 比如说 xff0c 当设备正在充电的时候 xff
  • 如何利用github打造博客专属域名

    转载请标明出处 xff1a http blog csdn net lmj623565791 article details 51319147 xff1b 本文出自 张鸿洋的博客 一 概述 哈 xff0c 本篇博客不属于Android技术类的
  • 基于HTML5实现的在线3D虚拟试衣系统(试衣间)解决方案

    3D虚拟试衣系统的使用场景主要是在线电商或数字营销 xff0c 为品牌服装 服饰 饰品添加高端3D虚拟购物动效 xff0c 提升用户感官体验和交互体验 要研发这样的在线系统 xff0c 有2个方向 xff0c 一个是使用Flash或Unit
  • 2011移动开发者大会亮点之一:六大精彩主题论坛抢鲜看

    2011中国移动开发者大会将是2011年度中国最大规模的移动盛事 本次大会全面覆盖软件应用和服务 平台 运营商 终端 芯片等移动产业链各个领域 xff0c 与此同时 xff0c 专注于产业链中最活跃的因素 应用软件的研发 创新与商业模式 x
  • collections的max()

    java util Collections的max方法可以获得集合中的最大值 xff1b 之前取map的最大key值 xff0c 还得自己写方法 xff0c 原来有现成的 xff1b max Collection lt extends T
  • “河软CSDN2011级表彰暨实习动员大会”顺利召开!

    9点30分 伴随着激昂的开场曲 xff0c 主持人走到台前 xff01 河软CSDN2011级表彰暨 实习动员大会即将开始 xff0c 请各位嘉宾入场 xff01 他们分别是 CSDN教育事业部总经 理李天山先生 河北软件职业技术学院 软件
  • ubuntu系统adb shell无法连接设备解决方法

    1 问题描述 xff1a alex 64 ubuntu adb shell daemon not running starting now at tcp 5037 daemon started successfully error insu
  • IT毕业生给学弟学妹们的真心话——离校座谈记录

    活动 xff1a 2009级毕业生离校前座谈 地点 xff1a 烟台大学计算机学院4409学业指导工作室 组织 xff1a 烟台大学CSDN高校俱乐部 时间 xff1a 2013年6月1日 上午8 30 参加人员 xff1a 主持人 xff
  • 生活就是工作学习锻炼身体

    多做事情多学习 少浪费时间 业精于勤荒于嬉 xff0c 行成于思而毁于随
  • golang之路--时间格式化

    有人问了问go的时间格式化问题 xff0c 于是乎自己尝试了下 xff0c 发现巨坑爹 xff0c 不按常理出牌啊 format的竟然模版必须如下面的每个数字 fuck t 61 time Unix 1362984425 0 nt 61 t
  • 生产者消费者模式C++程序模拟实现

    关于生产者和消费者的分析可以参考 xff1a http blog csdn net kenden23 article details 16340673 这里是利用C 43 43 简单模拟一个生产者消费者的工作模式 没有考虑到同步问题 操作了
  • Active MQ C++实现通讯

    Active MQ C 43 43 实现通讯 Kagula 2011 9 13 简介 在参考资料 2 的基础上介绍如何用C 43 43 调用Active MQ的客户端API 环境 xff1a 1 Windows XP SP3 2 Visua
  • OA工作流设计思路——请大神点评啊

    lt p gt OA工作流设计思路 请大神点评啊 xff0c 很多可能想的不是很到位 lt p gt lt p gt 此设计思路暂时没有包含详细的设计 xff0c 就是一个方向 xff0c 请大神指正下 xff0c 然方案更加完善 xff0
  • 解决Spring AOP 事务 配置 失效原因

    采用AOP配置声明式事务有5种方式 xff0c 下面只说关于采用TransactionInterceptor事务拦截器的方式 xff0c 配置程序如下 xff1a transactionManager xff1a lt bean id 61