代码抛出异常后进行事务回滚的两种方式(Spring @Transactional注解)详解编程语言

需求

在service层的某个方法中,在执行完一个对数据库的写方法后,抛出异常,再执行另一个对数据库的写方法,伪代码如下:

@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(); 
    } 
} 

回滚写法

写法一:方法抛异常

这种写法可以在方法处抛出异常,也可以不抛出(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(); 

完整方法:

@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(); 
    } 
} 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/19599.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论