【Spring事务详解】--- 3.事务失效的八种场景

前言

Spring事务详解连载

【Spring事务详解】— 1.事务传播的案例演示
【Spring事务详解】— 2.事务应用的注意事项
【Spring事务详解】— 3.事务失效的八种场景
【Spring事务详解】— 4.事务管理器的架构分析
【Spring事务详解】— 5.事务管理器TransactionSynchronizationManager分析
【Spring事务详解】— 6.事务创建的流程分析
【Spring事务详解】— 7.事务提交、回滚的流程分析
【Spring事务详解】— 8.beforeCommit、beforeCompletion、afterCommit、afterCompletion实现分析

这篇文章主要针对事务失效的情况来分析,应该也是最常遇到的问题。

事务失效的八种场景

1.异常未抛出

被捕获的异常一定要抛出,否则是不会回滚的。

// t1Service
@Transactional
public void func() {
    try {
        testMapper.updateT1();
        t2Service.func();
        int i = 1 / 0;
    } catch (Exception e) {
    	// 异常捕获了,未抛出,导致异常事务不会回滚。
        e.printStackTrace();
    }
}

// t2Service
@Transactional
public void func() {
    testMapper.updateT2();
}

2.异常与rollback不匹配

@Transactional默认情况下,只会回滚RuntimeExceptionError及其子类的异常,如果是受检异常或者其他业务类异常是不会回滚事务的。

@Transactional
public void func() throws Exception {
    try {
        testMapper.updateT1();
        t2Service.func();
        int i = 1 / 0;
    } catch (Exception e) {
    	// 默认情况下非运行时异常不会回滚
        throw new Exception();
    }
}

修改方式也很简单,@Transactional支持通过rollbackFor指定回滚异常类型

// 改成rollbackFor = Exception.class即可
@Transactional(rollbackFor = Exception.class)
public void func() throws Exception {
    try {
        testMapper.updateT1();
        t2Service.func();
        int i = 1 / 0;
    } catch (Exception e) {
        throw new Exception();
    }
}

3.方法内部直接调用

func2方法是由func调用,虽然func2方法上加了@Transactional注解,但事务不会生效,testMapper.updateT2()执行的方法并不会回滚

public void func() {
    testMapper.updateT1();
    func2();
}
@Transactional
public void func2() {
    testMapper.updateT2();
    int i = 1 / 0;
}

修改方式也很简单,通过注入的方式调用即可

@Service
public class T1Service {

    @Resource
    private TestMapper testMapper;
   
   // 注入T1Service对象
    @Resource
    private T1Service t1Service;

    public void func() {
        testMapper.updateT1();
        // 通过注入的方式调用自身的方法
        t1Service.func2();
    }

    @Transactional
    public void func2() {
        testMapper.updateT2();
        int i = 1 / 0;
    }
}

小插曲,SpringBoot 2.6.0版本开发,默认禁止循环依赖,所以如果你使用的版本是2.6.0之后的,那么启动会遇到如下报错

As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

修改方式:在配置文件中把允许循环依赖打开即可。

spring.main.allow-circular-references=true

当然,你也可以直接使用AopContext的方式

public void func() {
    testMapper.updateT1();
    T1Service t1Service = (T1Service) AopContext.currentProxy();
    t1Service.func2();
}
@Transactional
public void func2() {
    testMapper.updateT2();
    int i = 1 / 0;
}

4.在另一个线程中使用事务

Spring事务管理的方式就是通过ThreadLocal把数据库连接与当前线程绑定,如果新开启一个线程自然就不是一个数据库连接了,自然也就不是一个事务。

t2Service.func()方法操作的数据并不会被回滚

@Transactional
public void func() {
    testMapper.updateT1();
    new Thread(() -> t2Service.func()).start();
    int i = 1 / 0;
}

5.注解作用到private级别的方法上

当你写成如下这样时,IDEA直接会给出提示Methods annotated with ‘@Transactional’ must be overridable 原因很简单,private修饰的方式,spring无法为其生成代理。

public void func() {
    t1Service.func2();
}
@Transactional
private void func2() {
    testMapper.updateT1();
    int i = 1 / 0;
}

在这里插入图片描述

6.final类型的方法

这个与private道理是一样的,都是影响了Spring生成代理对象,同样IDEA也会有相关提示。
在这里插入图片描述

7.数据库存储引擎不支持事务

注意,如果你使用的是MySQL数据库,那么常用的存储引擎中只有InnoDB才支持事务,像MyISAM是不支持事务的,其他存储引擎都是针对特定场景下使用的,一般也不会用到,不做讨论。
在这里插入图片描述

8.事务的传播类型

前面的文章中已经对事务的传播类型做过介绍了,有的传播类型会以非事务方式执行,有的传播则会新开启一个事务,这些都需要额外注意。

REQUIRED:支持当前事务,如果当前不存在则新开启一个事务(默认配置)
SUPPORTS:支持当前事务,如果当前不存在事务则以非事务方式执行
MANDATORY:支持当前事务,如果当前不存在事务则抛出异常
REQUIRES_NEW:创建一个新事务,如果当前已存在事务则挂起当前事务
NOT_SUPPORTED:以非事务方式执行,如果当前已存在事务则挂起当前事务
NEVER:以非事务方式执行,如果当前已存在事务则抛出异常
NESTED:如果当前存在事务,则在嵌套事务中执行,否则开启一个新事务
  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
spring-security-oauth2-2.2.3.release.jar是一个用于实现基于OAuth 2.0协议的安全认证和授权的Java库。OAuth 2.0协议是一种用于授权的开放标准,它允许用户通过授权代理向第三方应用程序授权访问受保护的资源,而无需将用户的凭证(例如用户名和密码)透露给第三方。 spring-security-oauth2-2.2.3.release.jar提供了一套面向Spring应用程序的OAuth 2.0认证和授权解决方案。它可以轻松地将OAuth 2.0集成到现有的Spring应用程序中,并提供了一系列的API和类,使开发人员可以方便地实现OAuth 2.0认证和授权流程。 使用spring-security-oauth2-2.2.3.release.jar,开发人员可以通过配置和自定义一些核心组件(例如TokenStore、AuthorizationServer和ResourceServer)来实现OAuth 2.0的四种授权类型:授权码模式、密码模式、客户端模式和简化模式。通过这些授权类型,开发人员可以实现不同的应用场景和需求。 此外,spring-security-oauth2-2.2.3.release.jar支持使用不同的存储机制来存储和管理OAuth 2.0令牌,例如内存存储、数据库存储和Redis存储。开发人员可以根据自己的需求选择并配置合适的存储机制。 总的来说,spring-security-oauth2-2.2.3.release.jar提供了一种简单、可扩展且安全的方式来实现OAuth 2.0认证和授权。无论您是开发面向Web、移动还是其他类型应用程序,该库都能帮助您轻松地实现与第三方应用程序的安全集成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值