spring+mabatis中声明式事务不回滚
参考:https://www.cnblogs.com/zeng1994/p/8257763.html
https://www.cnblogs.com/lxl57610/p/7866165.html
声明式事务:就是使用SpringAop配置事务,这种方式大大的简化了编码。需要注意的是切入点表达式一定要写正确。
事务不回滚的产生原因:
- (1)声明式事务配置切入点表达式写错了,没切中Service中的方法
- (2)在Service层的方法中,把异常给try catch了,但catch里面只是打印了异常信息,没有手动抛出RuntimeException异常。因为将异常捕获,并且在catch块中不对事务做显 式提交(或其他应该做的操作如关闭资源等)=生吞掉异常;
- (3)在Service层的方法中,抛出的异常不属于运行时异常(如IO异常),因为Spring默认情况下是捕获到运行时异常就回滚
- (4)在Service层的方法中,把异常给try-catch-finally了,catch里手动抛出了RuntimeException异常,但是由于在finally里使用了return,所以显式地消化掉try、catch块中的 异常信息,屏蔽了错误的发生(我遇到的)
- (5)只有非只读事务才能回滚的,只读事务是不会回滚的
解决办法:
(1)检查切面设置
(2)在service层处理事务,从catch中手动抛出RuntimeException异常,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异 常并处理。
/**
* Service层
*/
public int addProvider(Provider provider) { int result = 0; try { result = providerMapper.addProvider(provider); int i = 1/0; } catch (RuntimeException e) { e.printStackTrace(); result = 0;
//手动抛出RuntimeExceprion异常 throw new RuntimeException(); }
//不要将return语句放入finally中 return result;
/**
* Service的上层
*/
public class TestProvider { private static Logger log = Logger.getLogger(TestProvider.class); @Test public void testAddProvider() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext-mybatis.xml"); ProviderService providerService = (ProviderService)ac.getBean("providerService"); Provider provider = new Provider(); provider.setProCode("JK_GY009"); provider.setProName("xx市随便一家公司"); provider.setProDesc("初次合作伙伴,主营业务:还没想好"); provider.setProContact("真聪明"); provider.setProPhone("13333333333"); provider.setProAddress("xx市xx区"); provider.setProFax("0755-27182281"); provider.setCreationDate(new Date()); int result = 0;
//捕捉并处理Service方法的异常 try { result = providerService.addProvider(provider); } catch (RuntimeException e) { e.printStackTrace(); } finally { log.debug(result); }
} }
(3)或者service中的方法中不做异常捕获
(4)或者在catch后面写一句回滚代码(TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();)来实现回滚,这样的话,就可以在抛异常后也能return 返 回值;比较适合需要拿到Service层的返回值的场景。
/** * Service层 */ @Override public int addProvider(Provider provider) { int result = 0; try { result = providerMapper.addProvider(provider); int i = 1/0; } catch (RuntimeException e) { e.printStackTrace(); result = 0; //手动回滚 //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return result; }
(5)如果Service层会抛出不属于运行时异常也要能回滚,那么可以将Spring默认的回滚时的异常修改为Exception,这样就可以保证碰到什么异常都可以回滚。
1.声明式事务,在配置里面添加一个rollback-for,代码如下
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
2.注解事务,直接在注解上面指定,代码如下
@Transactional(rollbackFor=Exception.class)

浙公网安备 33010602011771号