Spring中的事务回滚

引文

当我们在Spring中进行事务操作(e.g., 向数据表添加数据时), 如果程序在执行中出现异常,我们一定希望进行/了解本次基于的事务数据库操作是否会回滚(Rollback),那么我们就以一定的现实操作为例查看说明事物操作时如果出现异常时事物是否会进行回滚。

示例代码介绍

实体类

实体类是一个简单的User表,其中ID为自增长

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class User10 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;
}

Repository接口

Repository是一个基于BaseRepository(JPARpository)的拓展类

@Repository
public interface UserRepository10 extends BaseRepository<User10,Integer> {
}

Service类

Service类只有一个添加用户方法,开启事物(@Transactional)

@Service
@Transactional
public class UserService10 {
    @Autowired
    private UserRepository10 userRepository10;

    public void addUser(User10 user){
        userRepository10.save(user);
    }
}

实验

正常情况下

在正常情况下我们通过下列实验代码向数据库添加名为Alice的用户

	@Test
    public void addUserTest() {
        User10 user = new User10();
        user.setName("Alice");
        userService10.addUser(user);
    }

可以看到数据库插入一条数据:
Spring中的事务回滚_第1张图片

出现受检异常

捕获受检异常

在出现受检异常(我们这里以IO异常为例)并进行捕获的情形下我们通过下列实验代码向数据库添加名为Bob的用户,Service修改后的代码如下:

    public void addUser(User10 user) {
        userRepository10.save(user);
        try {
            Files.readString(Path.of("A:/not_exist.a"));
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

测试代如下:

    @Test
    public void addUserTest() {
        User10 user = new User10();
        user.setName("Bob");
        userService10.addUser(user);
    }

这里程序测试报错:
Spring中的事务回滚_第2张图片

但是我们看到测试时Idea报错且数据库成功插入,并未回滚:
Spring中的事务回滚_第3张图片

抛出异常

在出现受检异常(我们这里以算术异常为例)但直接抛出的情形下我们通过下列实验代码向数据库添加名为Cayce的用户,Service修改后的代码如下:

    public void addUser(User10 user) throws IOException {
        userRepository10.save(user);
        Files.readString(Path.of("A:/not_exist.a"));

    }

测试代码如下:

    public void addUserTest() throws IOException {
        User10 user = new User10();
        user.setName("Cayce");
        userService10.addUser(user);
    }

这里程序仍然报错。我们继续观察事物继续回滚:
Spring中的事务回滚_第4张图片
可以发现事物仍然正常进行,没有回滚。因此我们可以得出结论,当事物进行中出现受检异常时,事物不会回滚。

出现非受检异常

在这里我们直接抛出RuntimeException进行加入名为David用户的测试。
Service修改后的代码如下:

    public void addUser(User10 user) {
        userRepository10.save(user);
        throw new RuntimeException();
    }

因为非受检异常不需要显式捕获,我们的测试代码如下:

    public void addUserTest() {
        User10 user = new User10();
        user.setName("David");
        userService10.addUser(user);
    }

这里测试继续报错:Spring中的事务回滚_第5张图片
我们继续观察事务是否回滚:
Spring中的事务回滚_第6张图片
可以发现,事务回滚了。
因此我们发现:当事物进行中出现非受检异常时,事务回滚。
此外还有一个有趣的事情,我们以正常方式加入David后,观察Id值:
Spring中的事务回滚_第7张图片
我们可以发现刚才因为回滚而产生的id=4的对象被跳过

结论

 
至此我们可以得出结论:

  • 当事务中出现受检异常时,事务不会回滚,当事务中出现非受检异常时,事务回滚
  • 我们可以使用此现象来主动抛出非受检异常进行事务回滚操作

你可能感兴趣的:(JAVA,数据库,spring,java,mybatis)