聊一聊使用Spring事物时不生效的场景

简介: 今天介绍一下Spring事物不生效的场景,事物是我们在项目中经常使用的,如果是Java的话,基本上都使用Spring的事物,不过Spring的事物如果使用不当,那么就会导致事物失效或者不回滚,最终导致数据不一致,所以很有必要去研究一下Spring事物不生效的一些场景,避免掉坑。

前言


今天介绍一下Spring事物不生效的场景,事物是我们在项目中经常使用的,如果是Java的话,基本上都使用Spring的事物,不过Spring的事物如果使用不当,那么就会导致事物失效或者不回滚,最终导致数据不一致,所以很有必要去研究一下Spring事物不生效的一些场景,避免掉坑。


下面我们意义列举不生效的场景,并给出解决方法。


一.类没被Spring管理


如果我们的类没有被Spring管理,那么即使使用了Spring事物也不会生效,要让Spring管理我们的类,需要标注@Component,@Service等注解。


二.没有标注@Transactional注解的方法调用了标注@Transactional注解的方法


如果一个方法没有使用@Transactional注解,但是它去调用了带@Transactional注解的方法,那么当前方法的事物不生效。


public void saveUser(User user) throws Exception {
        save(user);
    }
    @Transactional(rollbackFor = Exception.class)
    public void save(User user) {
        try {
            userDao.save(user);
            exceptionMethod();
            roleService.save(user.getRole());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


如上所示,saveUser方法调用了save方法,但是saveUser没有标@Transactional注解,而它调用了save方法,save方法标了@Transactional,不过事物不会生效,这是因为方法没被代理,直接是普通方法调用,所以事物自然不生效。


如果一个方法中调用了其他方法,需要在主方法上加@Transactional注解这个方法才能被代理,如下代码,当然,远程调用@Transactional就不生效了,就需要分布式事物了。


@Transactional(rollbackFor = Exception.class)
    public void saveAnnotation(User user) throws Exception {
        save(user);
    }
    public void save(User user) {
        try {
            userDao.save(user);
            exceptionMethod();
            roleService.save(user.getRole());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


三.异常使用不正确


如果异常使用不当,那么事物也不会生效,这里的异常有两种,一种是我们抛出的异常,一种是@Transactional注解所接受的异常。


1.如果我们在程序代码中自己捕获了异常导致Spring事物捕获不到异常,那么事物也不会生效,如下,exceptionMethod方法捕获了异常并打印异常信息,那么异常并不会被Spring事物捕获到,所以事物并不会回滚。


@Transactional(rollbackFor = Exception.class)
    public void saveAnnotation(User user) throws Exception {
        userDao.save(user);
        exceptionMethod();
        roleService.save(user.getRole());
    }
    private void exceptionMethod() throws Exception {
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


如果需要事物回滚,那么就需要将异常抛到saveAnnotation方法,这样Spring事物才能感知到异常,从而进行事物回滚。


2.@Transactional注解有一个属性rollbackFor,它代表回滚的异常,也就是说只有捕获到这种异常事物才会回滚,它默认的是RunTimeException。


@Transactional
    public void saveAnnotation(User user) throws Exception {
        userDao.save(user);
        exceptionMethod();
        roleService.save(user.getRole());
    }
    private void exceptionMethod() throws Exception {
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            throw new Exception("抛出异常");
        }
    }


如上代码,exceptionMethod方法抛出了Exception异常,而@Transactional注解我们没有指定rollbackFor,所以使用的是默认的RunTimeException,所以事物不能回滚,如果我们需要事物回滚,需要让rollbackFor指定的异常是抛出异常的父类或者和自己一样才行,如下所示。


@Transactional(rollbackFor = Exception.class)
    public void saveAnnotation(User user) {
        userDao.save(user);
        exceptionMethod();
        roleService.save(user.getRole());
    }
    private void exceptionMethod() {
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            throw new ArithmeticException("运算异常");
        }
    }


四.不正确的传播行为


如果传播行为使用的是NOT_SUPPORTED,那么事物无法回滚。NOT_SUPPORTED表示当前方法不应该有事务,如果有事务存在,将它挂起,以无事务状态运行。


@Transactional(propagation = Propagation.NOT_SUPPORTED)


五.方法修饰为private


如果方法以private修饰,那么方法将不会被代理,事物自然不会生效,不过如果在进行业务开发的时候,对于需要其它类进行调用的方法,我们都是以public修饰,因为如果以private修饰,其它类想要访问的话需要借助反射才能访问,在IDEA中,@Transactional方法如果修饰为private,会有错误提醒,但是运行不会报错。



不过一些场景我们可能需要反射调用,所以不应该避开这个问题,还是将其修饰为public。


六.数据库不支持事物


如果数据库不支持事物,那么即使项目中使用了Spring事物,也不会生效,因为Spring的事物最终也是JDBC的事物,JDBC事物也要数据库支持事物才行,MySQL中MyISAM存储引擎不支持事物,InnoDB才支持事物。


七.没有配置事务管理器,导致事务失效。


使用非SpringBoot项目,需要配置PlatformTransactionManager,需要加上@EnableTransactionManagement注解,如果是SpringBoot项目,那么可以不用配置,因为SpringBoot默认帮我们装配好了,我们直接使用就好。


目录
相关文章
|
16小时前
|
Java 数据库 Spring
Spring事务失效的场景详解
Spring事务失效的场景详解
39 0
|
16小时前
|
Java Spring 容器
Spring的AOP失效场景详解
Spring的AOP失效场景详解
141 0
|
16小时前
|
缓存 NoSQL Java
Spring Boot项目中热点场景详解(万字总结)
Spring Boot项目中热点场景详解(万字总结)
|
16小时前
|
Java Shell 测试技术
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
40 0
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
|
7月前
|
Java 数据库连接 数据库
Spring的事务那些场景会失效?
Spring的事务那些场景会失效?
51 0
|
8月前
|
Java API 文件存储
Spring很常用的@Conditional注解的使用场景和源码解析
今天要分享的是Spring的注解@Conditional,@Conditional是一个条件注解,它的作用是判断Bean是否满足条件,如果满足条件,则将Bean注册进IOC中,如果不满足条件,则不进行注册,这个注解在SpringBoot中衍生出很多注解,比如@ConditionalOnProperty,@ConditionalOnBean,@ConditionalOnClass等等,在SpringBoot中,这些注解用得很多。
98 0
|
16小时前
|
安全 Java Maven
Spring Boot常见企业开发场景应用、自动配置原理结构分析(三)
Spring Boot常见企业开发场景应用、自动配置原理结构分析
|
16小时前
|
Java 数据库连接 Spring
Spring Boot常见企业开发场景应用、自动配置原理结构分析(二)
Spring Boot常见企业开发场景应用、自动配置原理结构分析
|
16小时前
|
前端开发 Java 数据库连接
Spring Boot常见企业开发场景应用、自动配置原理结构分析(一)
Spring Boot常见企业开发场景应用、自动配置原理结构分析
|
9月前
|
缓存 Java Spring
什么是 Spring AOP 以及 使用方法 和 场景
什么是 Spring AOP 以及 使用方法 和 场景
126 0