事务回滚

 

需求
在service层的某个方法中,在执行完一个对数据库的写方法后,抛出异常,再执行另一个对数据库的写方法,为什么不会滚呢??是对Spring的事务机制就不明白。!! 
   默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。  
   spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过  
    
配置来捕获特定的异常并回滚  
  换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚


  解决方案: 
  方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
  方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法)

 

伪代码如下:

@Transactional
public void func() {
    dao.write(pojo1);
    throw new Exception("异常");
    dao.write(pojo2);
}

要求此时事务全部回滚,即pojo1和pojo2都不写进数据库。

单元测试代码
    @Test
    public void testTransactional() {
        User user = new User();
        user.setUid(9);
        user.setUsername("李四");
        user.setPassword("234");
        userService.createAndUpdate(user);
    }


不回滚写法
这种写法保留了createUser方法对数据库的写操作,而不执行UpdateUser方法,结果是把创建的User对象李四写进了数据库,但并没有重命名为admin。原因是抛出异常并捕获后,并没有触发事务回滚。所以代码结束后李四保留在了数据库中。

    @Override
    public void createAndUpdate(User user) {
        try {
            createUser(user);
            if (!user.getPassword().equals("123")) {
                throw new RuntimeException("密码不是123");
            }
            user.setUsername("admin");
            updateUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

1

回滚写法
写法一:方法抛异常
这种写法可以在方法处抛出异常,也可以不抛出(throws RuntimeException可写可不写)。

    @Override
    public void createAndUpdate(User user) throws RuntimeException {
        createUser(user);
        if (!user.getPassword().equals("123")) {
            throw new RuntimeException("密码不是123");
        }
        user.setUsername("admin");
        updateUser(user);
    }

写法二:try catch捕获异常
这种方法相比于不回滚的那种写法,只是在catch作用域内多加入了一行代码:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
1
完整方法:

    @Override
    public void createAndUpdate(User user) {
        try {
            createUser(user);
            if (!user.getPassword().equals("123")) {
                throw new RuntimeException("密码不是123");
            }
            user.setUsername("admin");
            updateUser(user);
        } catch (Exception e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
原文:https://blog.csdn.net/qq_15329947/article/details/84974302 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章