首页
Preview

Spring @Transactional 事务回滚处理

默认情况下,Spring Boot 事务是自动提交的。每个 SQL 语句都在自己的事务中执行并在执行后提交。请看下面的示例,即使发生异常,产品也会被插入数据库中。

这不应该是这样的。在某些情况下,多个事务在一个逻辑代码单元中运行。只有在没有异常发生的情况下,所有事务才应该提交。

在 Spring Boot 中,当使用 @Transactional 注释时,Spring Boot 隐式创建一个代理,该代理将创建一个连接到数据库。在执行代码时,将启动并提交事务,如果出现异常,则将回滚更改。

示例 1

在此示例中,我们添加了 @Transactional 注释,以便在出现异常时回滚事务。

这个例子证明了 @Transactional 注释可以在出现异常时回滚事务。请注意,Spring 默认只会在未检查到异常时回滚。

示例 2a

此示例显示,即使我们指定了 @Transactional 注释,已检查的异常也不会被回滚。

示例 2b

要回滚已检查异常,我们需要指定 <em>rollbackFor</em>

我们看到事务已成功回滚。

示例 3

在此示例中,我们添加了 try-catch 块以查看回滚是否仍在工作。

这不起作用。这是因为我们手动捕获了异常并处理它。因此,当前事务正在正常执行并提交。

示例 4

那么 嵌套事务 呢?从下面的示例中,createProduct()createOrder() 方法将在数据库中插入记录。createOrder() 方法抛出了运行时异常。这两个方法都已用 @Transactional 注释进行了注释。

createProduct()createOrder() 事务被回滚了。即使 createOrder() 方法发生了运行时异常。但是,由于它没有处理异常,这导致 createProduct() 事务也回滚。

示例 5

让我们添加 try-catch 块以处理 createProduct() 方法中的运行时异常。

奇怪?为什么两个记录都被回滚了?同时,我们也注意到了异常错误。

@Transactional 有一个名为 Propagation 的参数。Propagation 将定义事务边界。Spring 将根据传播设置启动和结束事务。默认情况下,传播设置为 REQUIRED。因此,如果存在活动事务,则 Spring 将使用它而不是创建新事务。因此,在上述场景中,即使我们在外部方法中捕获了异常,事务仍然会回滚。

示例 6

使用 Propagation REQUIRES_NEW,这将强制 Spring 创建一个子事务。

产品记录被写入数据库,订单记录被回滚。

示例 7

如果我们从未在外部方法中使用 try 和 catch 块,并且在内部方法中发生了异常,外部事务仍会提交吗?

我们看到两个事务都被回滚了。因为内部事务抛出了异常,外部事务检测到异常并且未被处理。因此,外部事务已被回滚。

示例 8

让我们看看异常是否发生在外部方法中。

@Transactional
public void createProduct() {
    System.out.println("------ createProduct ------");
    Product prod = new Product();
    prod.setDescription("This is createProduct method.");
    prod.setPrice(10);
    prod.setTitle("Create Product with runtime");
    productRepository.save(prod);
    orderController.createOrder();
    throw new RuntimeException("Create Product RuntimeException");
}@Transactional(propagation=Propagation.REQUIRES_NEW)
public void createOrder() {
    System.out.println("------ createOrder ------");
    Order order = new Order();
    order.setTitle("Create Order with propagation required_new");
    order.setDescription("This is createOrder method.");
    orderRepository.save(order);  
}

我们看到,由于 Propagation.REQUIRES_NEW,内部事务已成功提交。这迫使Spring在子事务中处理查询。一旦完成,外部事务将恢复,并且在此时发生异常,因此它被回滚。

附加说明

请注意,如果两个方法在同一个类中,则 @Transactional 注释将不会生效。它始终被视为一个事务,因此即使我们指定了 Propagation.REQUIRES_NEW,它也不会起作用。一开始,我们谈到了Spring在看到注释 @Transactional 时创建代理。当你调用内部方法时,它将绕过代理。

谢谢阅读!

了解Spring事务传播

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
阿波
The minute I see you, I want your clothes gone!

评论(0)

添加评论