`
salazar
  • 浏览: 31001 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

采用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> 
 

 

2
0
分享到:
评论
1 楼 cucmber 2012-12-19  
遇到这个问题。在xml文件里自定义了异常可是依然失效。

相关推荐

    springAop事务配置

    本篇将详细讲解Spring AOP如何进行事务配置,包括注解和非注解两种方式。 1. **注解方式的事务管理** - **@Transactional**:这是Spring提供的核心注解,用于标记在一个方法或类上开启事务。当被注解的方法执行时...

    Spring事务管理失效原因汇总

    在Spring中,事务失效的具体原因可能包括但不限于以下几点: 1. 在非public方法上使用@Transactional注解。只有在public方法上,Spring的代理机制才会生效。 2. 类或方法使用了final修饰,导致无法被代理。 3. 方法...

    springboot实现多数据源而且加上事务不会使aop切换数据源失效

    本示例主要讲解如何使用Spring Boot结合MyBatis实现多数据源切换,并确保AOP事务管理仍然有效。 首先,我们需要配置多数据源。在Spring Boot中,可以使用`DataSource`接口的实现类,如`HikariCP`或`Druid`,创建两...

    线程池中使用spring aop事务增强

    这是因为在多线程环境下,`job`方法的调用并没有通过Spring的AOP代理,而是直接由普通实例执行,导致事务管理失效。 Spring AOP通常通过动态代理(JDK动态代理或CGLIB)来实现,当方法通过代理调用时,会触发AOP...

    解决osgi spring 事务配置问题

    这篇博客文章“解决osgi spring 事务配置问题”可能探讨了如何在这样的环境下正确设置和管理事务。 首先,Spring的事务管理主要依赖于AOP(面向切面编程)来实现,通过定义事务边界,如`@Transactional`注解,来...

    Spring的事务10种常见失效场景总结.zip

    5. **回调方法中的事务失效**:在Spring AOP中,后置处理器(AfterReturningAdvice)不能感知到事务,因此在这些回调方法中无法进行事务操作。如果需要在回调中处理事务,应考虑使用其他回调机制,如`@AfterThrowing...

    Spring自定义切面事务问题

    2. **Spring 自定义切面事务失效的原因** - 当我们创建自定义切面并通过`@Aspect`注解将其标记为切面时,如果没有正确地处理事务管理器和切面之间的关系,可能会导致事务失效。 - 默认情况下,Spring 的AOP代理...

    在Spring AOP代理过的对象上支持dubbo annotation配置事物失效问题-附件资源

    在Spring AOP代理过的对象上支持dubbo annotation配置事物失效问题-附件资源

    使用spring aop对web 应用数据进行memcached缓存

    标题 "使用Spring AOP对Web应用数据进行Memcached缓存" 涉及到的关键技术是Spring AOP(面向切面编程)和Memcached,这是一种常见的高性能、分布式内存对象缓存系统。在Web应用程序中,使用缓存可以显著提高数据访问...

    Spring事务失效问题分析及解决方案

    Spring事务失效问题分析及解决方案 在本文中,我们将详细介绍 Spring 中的事务失效问题分析及解决方案。Spring 事务机制是基于 AOP 实现的,通过使用 @Transaction 注解来标注事务方法。然而,在实际开发中,可能会...

    springtransaction 事务管理

    Spring 事务管理是Spring框架的核心特性之一,它提供了一种在Java应用中处理事务的统一方式,无论是数据库事务还是程序中的逻辑事务。Spring事务管理主要包括编程式事务管理和声明式事务管理两种方式,使得开发者...

    aop编程jar包

    如果这个库出现问题,Spring可能无法找到或处理切面注解,进而导致AOP功能失效。 5. **问题解决** 如果在使用注解进行AOP编程时遇到问题,首先检查是否正确引入了aspectjrt.jar和aspectjweaver.jar,并确保它们的...

    springMVC AOP拦截拦截Controller等实现日志管理

    在Spring MVC中,AOP(面向切面编程)是一种强大的工具,可以让我们在不修改代码的情况下,对程序的特定部分进行增强,例如日志记录、事务管理或性能监控。在这个场景中,我们将讨论如何利用AOP来实现Controller的...

    解决springboot的aop切面不起作用问题(失效的排查)

    除了解决AOP切面不起作用的问题外,我们还可以使用AOP来实现全局配置事务。下面是一个简单的示例: ```java @Aspect @Configuration public class TransactionAdviceConfig { private static final String AOP_...

    Spring事务不生效.pdf

    本文将深入探讨Spring事务失效的常见原因,帮助开发者识别并解决这些问题。 首先,我们要明白Spring事务的工作原理。Spring采用AOP(面向切面编程)来实现事务管理,通过动态代理在方法执行前后插入事务处理逻辑。...

    spring事务总结.docx

    然而,在实际开发过程中,经常会遇到一些关于Spring事务的问题,如事务失效、事务回滚、大事务问题以及编程式事务等。本文将深入探讨这些问题,并给出相应的解决方案。 #### 一、事务不生效的原因及解决办法 1. **...

    什么情况会导致@Transactional事务失效?

    以下是一些可能导致`@Transactional`事务失效的情况: 1. **未启用事务管理**:如果你的应用没有配置Spring的事务管理器(如PlatformTransactionManager),或者没有开启AOP代理(例如,使用@Component而不是@...

    SpringBoot内部调用事务不起作用问题的解决方案

    当我们使用 this 调用方式时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效。 二、解决方法 解决这个问题有多种方法,下面将介绍三个解决方法: 方法一:引入自身 bean 在类内部通过 @...

    spring杂谈 作者zhang KaiTao

    他还分享了解决数据库读写分离、错误处理、依赖注入失效等问题的经验,以及在特定环境下如IDEA内嵌Jetty运行Spring项目时可能遇到的异常处理。 总的来说,这些内容涵盖了Spring的多个重要方面,包括事务管理、AOP、...

Global site tag (gtag.js) - Google Analytics