配置事物:
@Configuration /**强制使用cglib代理时就把proxy-target-class设为true.*/ @EnableTransactionManagement(proxyTargetClass=true) public class DataBaseConfiguration implements TransactionManagementConfigurer{ @Bean(name="testpackageTransactionManager") @Qualifier("testpackageTransactionManager") public PlatformTransactionManager testpackageTransactionManager() { return new DataSourceTransactionManager(testpackageDataSource()); } }
事物回滚错误示例:
示例一:
@Transactional(value = "testpackageTransactionManager", rollbackFor = RuntimeException.class) @RequestMapping("/rollback") public void rollback() { try { TestEntity test = new TestEntity(); test.setMark("======rollback tran test========"); testMapper.insertSelective(test); throw new Exception("出错了========!"); } catch (Exception ex) { System.out.println("出错了回滚事物"); } }
被try catch处理的事物不会回滚。
下面的方法会成功回滚:
示例二:
手动回滚:
@Transactional(value = "testpackageTransactionManager", rollbackFor = RuntimeException.class) @RequestMapping("/rollback") public void rollback() { try { TestEntity test = new TestEntity(); test.setMark("======rollback tran test========"); testMapper.insertSelective(test); throw new Exception("出错了========!"); } catch (Exception ex) { System.out.println("出错了回滚事物");
//手动回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
示例三:
指定事物回滚rollbackFor = Exception.class ,抛出Exception、RuntimeException、DiyException(自定义继承自Exception的异常)异常都可以成功回滚
@Transactional(value = "testpackageTransactionManager", rollbackFor = Exception.class) @RequestMapping("/testTran3") public void testTran3() throws Exception { try { TestEntity test = new TestEntity(); test.setMark("======rollback tran test 2========"); testMapper.insertSelective(test); throw new Exception("出错了回滚事物==!"); } catch (Exception ex) { System.out.println("出错了回滚事物"); throw new Exception("出错了回滚事物");
//throw new RuntimeException("出错了回滚事物");
//throw new DiyException(); 继承自Exception的自定义异常
} }
示例四:
指定事物回滚rollbackFor =RuntimeException.class ,只有抛出RuntimeException类型的异常,才会回滚事物
/**事物回滚成功*/ @Transactional(value = "testpackageTransactionManager", rollbackFor = RuntimeException.class) @RequestMapping("/testTran4") public void testTran4() throws Exception { try { TestEntity test = new TestEntity(); test.setMark("======rollback tran test 2========"); testMapper.insertSelective(test); throw new Exception("出错了回滚事物==!"); } catch (Exception ex) { System.out.println("出错了回滚事物"); throw new RuntimeException("出错了回滚事物"); } }
为什么【示例一】不会滚呢??是对spring的事务机制就不明白。!!
默认spring 事务只在发生未被捕获的 RuntimeExcetpion时才回滚。
Spring Aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样Aop代理才能捕获到方法的异常,才能进行回滚,默认情况下Aop只捕获RuntimeExcetpion的异常,但可以通过 配置来捕获特定的异常并回滚换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new RuntimeExcetpion(),这样程序异常时才能被Aop捕获进而回滚
解决方案:
方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeExcetpion()语句,以便让Aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法)。