首页 > 技术文章 > Spring事务回滚

mr-yang-localhost 原文

配置事物:

@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();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法)。

推荐阅读