`

spring异常抛出触发事务回滚策略

    博客分类:
  • J2EE
阅读更多
Spring、EJB的声明式事务默认情况下都是在抛出unchecked exception后才会触发事务的回滚

测试用业务逻辑方法:
/**
 * 如果在spring事务配置中不为切入点(如这里的切入点可以定义成test*)配置事务在什么情况下回滚(格式:-引起回滚的异常类型)
 * 则spring默认只会在service方法抛出unchecked exception才会触发回滚
 */
public class TestServiceImpl extends Service implements TestService {

	/**
	 * 测试spring异常触发事务回滚的service方法
	 */
	public void testAddPerson(String name) throws Exception {
		TestPerson p = new TestPerson();
		p.setName(name);
		this.getHibernateGenericController().save(p);
		
		/*
		 * 制造RuntimeException
		 * 在spring默认的异常回滚策略下,该异常的抛出会触发事务的回滚,数据不会被插入
		 */
		throw new RuntimeException("抛出个运行时异常");
		
		/**
		 * 同样是unchecked exception,spring默认的异常回滚策略下Error的抛出也会触发事务的回滚,数据不会被插入
		 */
//		throw new Error();
		
		/**
		 * 即使是在spring默认的异常触发事务回滚策略(unchecked exception触发回滚)下,
		 * 如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚,数据被插入
		 * “将异常捕获,并且在catch块中不对事务做显式提交=生吞掉异常”
		 */
//		try {
//			throw new RuntimeException("这个抛出的运行时异常会被try-catch捕获");
//		} catch(Exception e) {
//			System.out.println("捕获到异常: " + e.getMessage());
//		}
		
		/**
		 * 因为Exception类是个checked exception,所以这里抛出的异常不会触发事务的回滚,数据被插入
		 */
//		throw new Exception("a Exception instance");
		
		/**
		 * 该BaseException继承自Exception,也为checked exception,抛出它后:
		 * spring默认的回滚策略下,事务未回滚, 数据被插入;
		 * 在TransactionProxyFactoryBean的transactionAttributes中配置
					<prop key="test*">
						... ...,-BaseException
					</prop>
			后,事务回滚,数据未被插入
		 */
//		throw new BaseException("一个BaseException");
	}

}

关于TransactionProxyFactoryBean的transactionAttributes中字符串的值(定义自TransactionAttributeEditor):
is a transaction attribute descriptors that parsed via TransactionAttributeEditor
见本博客:http://wuaner.iteye.com/admin/blogs/567792

单元测试代码:
public class TestSpringDefaultRollback extends TestCase {

	private static ApplicationContext context = new ClassPathXmlApplicationContext("resource/xxx/applicationContext.xml");
	public void testDefaultRollback() throws Exception{
		TestService testServiceImpl = (TestService)context.getBean("testService");
		testServiceImpl.testAddPerson("张三");
	}
}



将异常捕获,并且在catch块中不对事务做显式提交(或其他应该做的操作如关闭资源等)=生吞掉异常

spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常).
如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。
一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。
由此可以推知,在spring中如果某个业务方法被一个
try {
	//bisiness logic code
} catch(Exception e) {
	//handle the exception
}

整个包裹起来,则这个业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致spring异常抛出触发事务回滚策略失效。
不过,如果在catch代码块中采用页面硬编码的方式使用spring api对事务做显式的回滚,这样写也未尝不可。


分享到:
评论
5 楼 geyaandy 2012-11-04  
如果我要在catch块中 再次操作数据库(插入) (同一个连接) 能成功么
4 楼 龙腾盛世 2012-07-19  
   
3 楼 Wuaner 2011-04-16  
yuanyuan7891 写道
如果我在catch块中需要return数据又要spring回滚事务,要怎么办啊?

采用页面硬编码的方式使用spring api对事务做显式的回滚。
2 楼 yuanyuan7891 2011-04-16  
如果我在catch块中需要return数据又要spring回滚事务,要怎么办啊?
1 楼 yuanyuan7891 2011-04-16  
终于知道为什么我的事务没有处理了,原来被我在catch块中处理掉了,没有抛出异常啊。

相关推荐

Global site tag (gtag.js) - Google Analytics