首页 > 其他分享 >@Transactional注解事务失效的几种场景及原因

@Transactional注解事务失效的几种场景及原因

时间:2022-12-06 14:44:57浏览次数:50  
标签:回滚 场景 Transactional 事务 失效 test 注解 public

1. 介紹

在业务开发的许多场景中,我们会使用到通过事务去控制多个操作的一致性。比较多的就是通过声明式事务,即使用 @Transactional 注解修饰方法的形式。但在使用过程中,要足够了解事务失效的一些场景,提前规避在使用事务过程中出现事务失效的 bug 。下面就介绍下常见的事务失效的场景及原因分析。

2. 事务失效的场景及原因分析

场景一:数据库引擎不支持事务

以 Mysql 举例,在 5.5 版本之前,Mysql 默认的数据引擎都是 MyISAM 的,而 MyISAM 是不支持事务的;在 5.5 版本之后,默认的数据引擎是 InnoDB 的,它是支持事务的。而 Spring 对事务的管理实现又是基于数据库的,所以当数据库引擎不支持事务的时候,自然就不会有起作用的事务机制了。
如下:
mysql中创建表的时候是可以设置数据引擎的

场景二:事务所在类没有被 spring 管理

如下使用场景,当该类没有被 @Service 修饰时,是不会被 Spring 管理的,当然 @Transactional 事务注解就不能管理事务了。其实在使用过程中,当实现类没有使用 @Service 注解时,多数情况下在项目启动的时候会直接报错的。

// @Service
public class TestServiceImpl implements ITestService {

    @Override
    @Transactional
    public void test1() {
        // test code
    }

}

场景三:注解作用的方法,是非 public 的

先看下来自 Spring 官方的解释:
<code>When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

大概意思就是 @Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可以开启 AspectJ 代理模式

场景四:属性 rollbackFor 设置错误

事务机制默认是当捕获到 RuntimeException 异常时,才会触发回滚。所以当抛出 RuntimeException 以外的异常时,而又想触发事务的回滚机制,就需要对 rollbackFor 属性做设置了。

例如:
当 throw 了 Exception 异常时,想要触发事务回滚,就要设置@Transactional(rollbackFor = Exception.class)

    @Transactional(rollbackFor = Exception.class)
    public void test() {
        // test code
        if(1 == 1) {
            throw new Exception("Exception 异常");
        }
    }

场景五:属性 propagation 设置错误

通过设置 @Transactional(propagation = Propagation.NOT_SUPPORTED) 可以配置 Spring 的事务传播机制的,当事务传播机制设置为不支持事务是,事务也是不会生效的。

例如:
当设置为 propagation = Propagation.NOT_SUPPORTED 时,表示不以事务运行,当前若存在事务则挂起。

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void test1() {
        // test code

    }

场景六:调用同类中的方法

下面两种场景事务都是失效的,因为发生了直接的自我调用,没有经过代理。因为事务是基于代理实现的, 而这种情况会造成程序无法生成代理类,从而造成事务失效。
具体的解决方法,可以将该类通过注入的方式注入到自己中,再用注入的对象调用方法解决。
情况一:

@Service
public class TestServiceImpl implements ITestService {

    @Override
    public void test1() {
        // test code
        test2();
    }

    @Override
    @Transactional
    public void test2() {
        // test code
    }
}

情况二:

@Service
public class TestServiceImpl implements ITestService {

    @Override
    @Transactional
    public void test1() {
        // test code
        test2();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void test2() {
        // test code
    }
}

场景七:异常被捕获,无法触发事务回滚

事务机制的回滚,是 通过异常来触发事务回滚 的。在开发过程中,会出现异常被捕获处理了,而且没有再抛出新的异常,就会导致异常丢失,无法触发回滚。

不会触发回滚的情况:

    @Transactional
    public void test1() {
        // test code
        try {
            throw new  RuntimeException();
        } catch (RuntimeException e) {
            // 不做处理,虽然有异常,但异常丢失,无法触发事务回滚
        }
    }

会触发回滚情况:( catch 异常后,再抛出)

    @Transactional
    public void test1() {
        // test code
        try {
            throw new  RuntimeException();
        } catch (RuntimeException e) {
            // 不做处理,虽然有异常,但异常丢失,无法触发事务回滚
            throw e;
        }
    }

标签:回滚,场景,Transactional,事务,失效,test,注解,public
From: https://www.cnblogs.com/xiangningdeguang/p/16955161.html

相关文章

  • 光模块功能失效的原因有哪些?
    光模块主要用来将设备(一般指的是交换机或者路由器设备)中的电信号转换成光信号,然后通过一根光纤发射出去(由光模块的发射端实现),同时可以接收外部一根光纤发射过来的光信号且转......
  • 【重温SSM框架系列】10 - Spring AOP开发的两种方式(基于XML、基于注解)
    AOP开发​​概述​​​​基于XML的AOP开发​​​​1.导入AOP依赖包​​​​2.创建目标类和接口​​​​3.创建切面类(增强方法类)​​​​4.将目标类和切面类交给Spri......
  • Spring源码-04-注解Bean读取器
    Spring源码-04-注解Bean读取器AnnotatedBeanDefinitionReader一构造方法publicAnnotatedBeanDefinitionReader(BeanDefinitionRegistryregistry,Environmentenviro......
  • Spring Boot 最核心的 25 个注解
    SpringBoot最核心的25个注解1、@SpringBootApplication这是SpringBoot最最最核心的注解,用在SpringBoot主类上,标识这是一个SpringBoot应用,用来开启SpringB......
  • Spring纯注解方式使用AOP
    Aop配置类packagecom.mt.spring5.aopanno;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;......
  • Spring中@Async注解使用及配置
    Spring中@Async注解使用及配置参考文章:https://blog.csdn.net/weixin_42272869/article/details/123082657一、@Async注解的使用在使用spring框架中,可以非常简单方便的......
  • Redis 利用 incr 和 expire 来限流, 并发导致过期时间失效问题
    当某一个接口需要限流时,可以采用redis的incr来递增,记录访问次数,以及expire来设置失效时间.大概的代码如下:r=redis.Redis.connect()key="linyk3"......
  • @EnableEurekaServer注解不可用
    1.可能是springBoot版本和spingCloud版本不匹配parentpom做了如下修改<!--基于springboot开发--><parent><groupId>org.springframework.boot</groupId><artifactId......
  • AliasFor注解-1
    一、AliasFor注解@AliasFor注解用于声明注解属性的别名,常用于组合注解。二、使用场景1)在一个注解中显示为属性设置别名如下1.1定义一个ContextConfigurati......
  • SpringBoot 缓存注解的使用
    最近比较忙,没时间更新了。上一篇文章我说了如何使用Redis做缓存,文末我稍微提到了SpringBoot对缓存的支持。本篇文章就针对SpringBoot说一下如何使用。1、SpringBoot对缓存......