Spring事务


前置条件
*事务未失效(如果事务失效了,以下尝试都没有意义)
以下为可能导致事务失效的几种情况
1.内部调用:
如直接this.方法名() 或者 方法名();
测试Spring事务时,需要保证获取到的对象为非本类对象,Spring事务的实现本质为Aop生成的代理对象,方法内部调用时,没有调用到代理对象中切入的方法和操作;解决方式:1.实现ApplicationAware接口根据类型从容器中获取到本类生成的代理对象,这样事务才会生效 2.方法拆解到两个不同的类中,以下通过两个类来测试Spring的事务

2.数据库引擎不支持事务 使用的数据库以及引擎需要支持事务操作,如Mysql的引擎中Innodb才支持事务*

3.方法不是 public 的,这个同样适用于@Controller/@RestController等(之前由于写代码写的急,controller中有个方法一直报错,找了半天(由于系统的异常处理设计的很有问题,所以无法看到具体的报错异常,且代码无法本地运行,就很麻烦),原来是用了private)

4.没有被 Spring 管理 我们这里的事务是依赖于SpringAOP的,在生成对象后,会有一个生成代理类的过程(当然,也不是所有被Spring管理的类都需要代理类,但是Aop是需要的),所以你直接new出来的对象时没有不能通过注解式来实现Aop的,包括你自定义的切面也是如此(如日志切面、操作记录等)

5.数据源没有配置事务管理器 Spring的话好像必须配置,SpringBoot好像是已经开启了的(或者说是我们用的mybatis-plus)

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

6.设置了不支持事务

 @Transactional(propagation = Propagation.NOT_SUPPORTED)

7.异常被捕获,或者异常不匹配

    @Transactional
    public void updateOrder(Order order) {
        try {
            // update order 操作
        } catch {
            
        }
    }

8.异常类型不匹配(如默认为RuntimeException及其子类,而你抛出的是大于RuntimeException的异常)

    @Service
	public class OrderServiceImpl implements OrderService {
	
	    @Transactional
	    public void updateOrder(Order order) {
	        try {
	            // update order
	        } catch {
	            throw new Exception("更新错误");
	        }
	    }
	    
	}

验证@Transcational注解,在此方法被调用时,会根据你注解中的传播属性来确定你是否需要开启事务,或者事务与事务间如何处理(我的理解是主事务只要支持事务,子事务中@Transcational传播属性相同时得到的结果是一致的)

1.Spring传播属性

1.传播属性分类

REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

2.备注

通常我们只会用到@Transactional(propagation = Propagation.REQUIRED),在特殊需求的时候需要在一个方法内部提前提交一部分事务或者是让内部的一段代码处于单独的一个事务管理的时候需要用到REQUIRES_NEW

2.Propagation.REQUIRED(为主事务时)

1.当Propagation.REQUIRED遇上Propagation.REQUIRED

代码片段如下:

1.主事务方法

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void saveUser(SysUser sysUser) {
        //用的mybatis-plus 所以直接使用ServiceImpl中的save方法
        this.save(sysUser);
        //子事务方法
        logService.addUser(sysUser);
    }

2.子事务方法

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
    }

3.正常执行

    @ApiOperation(value = "新增管理员")
    @PostMapping("/save")
    public R save(@RequestBody UserReq req){
       SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(req,sysUser);
        sysUserService.saveUser(sysUser);
        return R.ok();
    }

4.执行结果

接口返回情况

在这里插入图片描述
管理员表
在这里插入图片描述
可以看到增加了一条记录
日志记录表
在这里插入图片描述
可以看到日志也正常加入

5.在子事务中抛出异常

主事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
    }

以上是没有异常出现的情况,此处在子事务新增一个除0异常
子事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
        int i = 1/0;
    }

测试
返回结果:(如下是因为出现了异常,异常处理有些问题,还需要完善,这里只做功能演示)
在这里插入图片描述
刷新管理员表的记录,发现数据并未增加
在这里插入图片描述

查看日志表,也没有新增的日志记录
在这里插入图片描述

6.在主事务中抛出异常

主事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
        int i  = 1/0;
    }

子事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
    }

执行结果
在这里插入图片描述
刷新管理员表,发现数据无新增
在这里插入图片描述
刷新日志表,发现数据无新增
在这里插入图片描述

7.结论

当主事务和子事务都是Propagation.REQUIRED时,不管是在子事务还是主事务中抛出异常,整个事务都会回滚,也就是说,他们两属于一个事务,所以同时成功或者同时失败。

2.当Propagation.REQUIRED遇上Propagation.REQUIRES_NEW

1.在子事务中抛出异常

主事务如下:

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
    }

子事务如下:

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
        int i  = 1/0;
    }

返回结果
刷新管理员表,13778222222的这条数据未插入
在这里插入图片描述
刷新日志表,没有新增数据
在这里插入图片描述

2.在主事务中抛出异常

主事务:

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
        int i  = 1/0;
    }

子事务:

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
    }

执行结果
在这里插入图片描述
刷新管理员表,数据无新增
在这里插入图片描述
刷新日志表,发现多处一条日志记录
在这里插入图片描述

3.结论

主事务传播属性为Propagation.REQUIRED,子事务传播属性为Propagation.REQUIRES_NEW时,子事务出现异常会导致主事务回滚,而主事务的异常不会影响子事务的提交

3.Propagation.REQUIRES_NEW(为主事务时)

1.当Propagation.REQUIRES_NEW遇到Propagation.REQUIRED

1.子事务代码出现异常

主事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
    }

子事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
        int i = 1/0;
    }

执行结果(username为33333结尾)

在这里插入图片描述
管理员表无新增
在这里插入图片描述
日志表无新增
在这里插入图片描述

2.当主事务代码出现异常时

主事务代码:

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
        int id = 1/0;
    }

子事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
    }

执行结果
在这里插入图片描述
刷新管理员表,无数据新增
在这里插入图片描述
刷新日志表,无数据新增
在这里插入图片描述

2.当Propagation.REQUIRES_NEW遇到Propagation.REQUIRES_NEW时

1.子事务代码抛出异常

主事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
    }

子事务代码

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
        int i = 1/0;
    }

执行结果:添加的137783333333
在这里插入图片描述
管理员表,无数据新增
在这里插入图片描述
查看日志表,无数据新增
在这里插入图片描述

2.主事务代码抛出异常

主事务:

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void saveUser(SysUser sysUser) {
        this.save(sysUser);
        logService.addUser(sysUser);
        int i = 1/0;
    }

子事务

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public void addUser(SysUser user) {
        SysLog log = new SysLog();
        log.setLogData(JSON.toJSONString(user));
        baseMapper.insert(log);
    }

执行结果:
在这里插入图片描述
管理员表无新增数据137783333333
在这里插入图片描述
此时,日志表多处来了一条数据

在这里插入图片描述
通过对比上面的Propagation.REQUIRED(主事务)+Propagation.REQUIRED(子事务)以及Propagation.REQUIRES_NEW(主事务)+Propagation.REQUIRES_NEW(子事务)分析;主事务上加的注解,对传播属性相同的子事务的流程处理结果都是一样的;也就是说,只要开启了事务,决定主事务和子事务之间如何影响的主要还是子事务上的传播属性。

4.结论

综合2.3 事务只是在方法被调用时考虑是否需要开启事务,是否需要将新事务加入已有事务以及如何建立已有事务和新事务的关系等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SinceThenLater

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

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

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

打赏作者

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

抵扣说明:

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

余额充值