项目中Spring 声明式事务使用的一些坑点分析02

项目中Spring 声明式事务使用的一些坑点分析02

        基于上次对"Spring 声明式事务使用的一些坑点分析01"分析后感觉还是有一定收获的,现在开始进行对Spring 事务进行更进一步的分析坑点,我之前在开发的时候有人好像这样告诉过我"只要在同一个service方法中有多个操作是对数据表进行更改(insert,update,delete)都需要在该方法上加上@Transactional(rollbackFor = Exception.class)",今天我就来分析一下在上面情况下其实不用加这个注解其实也是能回滚数据的。

1.     案例1:

@Override
public void handleNoTransactionAnnotation(){
	SecurityAddition record = new SecurityAddition();
	record.setAmt(new Double(20));
	record.setCard(System.currentTimeMillis()+"");
	record.setOrder_no("Order-"+System.currentTimeMillis());
	record.setName("张三");
	securityAdditionMapper.insert(record);
	
	throw new RuntimeException("抛出异常了...");
}

如上代码是SecurityAddition类对应security_addition表,对于security_addition表的插入后抛出了RuntimeException,分析:在项目配置文件中其实配置对应service方法的事务传播行为:<tx:method name="handle*" propagation="REQUIRED" />,所以当代码执行到handleNoTransactionAnnotation这个方法的时候就会判断:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这里是没有事务创建一个事务,这个方法内部的代码执行完后就会提交事务,所以这里代码没有执行完就抛出RuntimeException所以security_addition表中是没有插入数据的,因为Spring 发现出错了,它会回滚,其实就是不提交目前这个手动事务。

2.     案例2:

@Override
public void handleNoTransactionAnnotation() {
	SecurityAddition record = new SecurityAddition();
	record.setAmt(new Double(20));
	record.setCard(System.currentTimeMillis()+"");
	record.setOrder_no("Order-"+System.currentTimeMillis());
	record.setName("张三");
	securityAdditionMapper.insert(record);
		
	Admin admin = new Admin();
	admin.setCreateTime(new Date());
	admin.setId(28);
	admin.setDoctorId(101);
	admin.setHospitalId(101);
	admin.setPassword("123456");
	admin.setPayName("张三");
	admin.setState(1);
	admin.setToken("88888888");
	admin.setAccount("zhangsan");
	admin.setType("USER");
	adminMapper.insert(admin);
	
	throw new RuntimeException("抛出异常了...");
}

那么对于多表操作或者多个同表变更操作,这个时候如上代码还能正常回滚吗? 答案是:可以的,原因:他们二个表都是在同一个数据源下的,这里方法内部是使用的一个事务,而不是一个操作一个事务,所以这里即使在代码最后抛出RuntimeException(这里包括RuntimeException的所有子类异常)都是能将当前同一事务下的多个操作进行回滚的。

3.     案例3:

@Override
public void handleNoTransactionAnnotation() throws Exception{
	SecurityAddition record = new SecurityAddition();
	record.setAmt(new Double(20));
	record.setCard(System.currentTimeMillis()+"");
	record.setOrder_no("Order-"+System.currentTimeMillis());
	record.setName("张三");
	securityAdditionMapper.insert(record);
		
	Admin admin = new Admin();
	admin.setCreateTime(new Date());
	admin.setId(28);
	admin.setDoctorId(101);
	admin.setHospitalId(101);
	admin.setPassword("123456");
	admin.setPayName("张三");
	admin.setState(1);
	admin.setToken("88888888");
	admin.setAccount("zhangsan");
	admin.setType("USER");
	adminMapper.insert(admin);
	
	// ** 注意这里异常变了 **
	throw new Exception("抛出异常了...");
}

这里我将RuntimeException异常改为了Exception异常了,这个时候能正常回滚吗?答案是:不能,因为 Spring 中回滚是默认RunTimeException才会回滚,如果抛出的不是RunTimeException,Spring是默认不会回滚的。

所以综合上述案例效果可以得出结论:只要在对应service方法中只要你能保证抛出的异常都是RuntimeException异常那就可以不用加@Transactional(rollbackFor = Exception.class)这个注解。那我们什么时候才会用到这个注解了,就是当我们需要对service方法中抛出Exception也能回滚事务的操作下,我们就可以使用到这个注解。

异常相关知识可以参考博客:JAVA 异常分类与理解

4.    

猜你喜欢

转载自my.oschina.net/qrmc/blog/1807085
今日推荐