SpringBoot 中 @Transactional 的使用细节

1.spring boot 中事物的使用 (当前指代的不是多数据源,只有一个数据源的前提下)

<1> 在springboot 启动类上加上允许使用事物注解

@EnableTransactionManagement

<2> 就这么简单的一个操作,更主要的是了解@Transactional 的一些特性,到底该怎么使用,什么时候使用。

事物的四个特性想必大家应该都知道,原子性(最小的整体,不可分割),一致性(都成功或都失败),隔离性(事物间互不干扰),持久性(保存的数据库)。

原子性 (atomicity):强调事务的不可分割。
一致性 (consistency):事务的执行的前后数据的完整性保持一致。
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰 。
持久性(durability) :事务一旦结束,数据就持久到数据库。
<3> 进到@Transactional 注解中看一下 

propagation:该属性用于设置事务的传播行为。

isolation:该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout:该属性用于设置事务的超时秒数(单位为秒),默认值为-1表示永不超时

readOnly:该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。

rollbackFor:

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName:

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")

指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollBackFor:

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollBackForClassName:

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")

指定多个异常类名称:@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

<4>下面需要了解一下事物传播属性中可以设置的值 Propagation是一个枚举类 

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);

    private final int value;

    private Propagation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }
}

如上,是spring boot 或者说spring支持的7中事物传播级别,说一下不同的隔离级别以及使用场景,

在说下文之前,我要说一下,事物传播,传播的意思指代为被调用者将事物传递到调用者。这个过程为事物的传播过程。这句话我想如果理解会更好的理解这几种事物传播行为。

REQUIRED: 表示当前方法必须在一个具有事物的上下文中运行,如果客户端有事物,那么被调用端将在该事物中运行,否则的话重新开启一个事物,如果被调用端发生异常,那么调用端和被调用端事物都将回滚。

模拟一个场景(在俩个不同的servies中,PS:为什么指代发生在俩个类中,现在所有对象都交由Spring统一管理,而只有在代理对象之间进行调用的时候才能触发切面逻辑,跟踪代码的时候会发现,优先进入的CglibAopProxy代理类...)

俩个业务 A业务修改一个参数值改为150 ,B业务随后将该值改为1500。

    /** 业务A */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void transTest() {
        ParkParam parkParam1 = new ParkParam();
        parkParam1.setParamId(1);
        parkParam1.setParamValue("150");
        parkParamMapper.updateById(parkParam1);
        //调用业务B  
        parkCarService.testTrans();

    }
     /**业务B*/
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void testTrans() {
        ParkParam parkParam2 = new ParkParam();
        parkParam2.setParamId(1);
        parkParam2.setParamValue("1500");
        parkParamMapper.updateById(parkParam2);
        //模拟抛出异常
        int a = 9/0;
    }

OK,这是很正常的代码逻辑,结果也和大家想想中的一样,B发生异常,AB俩段逻辑同时回滚。但是如果我将调用B的逻辑try,catch 住。那这时候A会正常提交吗?我把A的业务逻辑改成如下。

 /**
     * 业务A 
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void transTest() {
        ParkParam parkParam1 = new ParkParam();
        parkParam1.setParamId(1);
        parkParam1.setParamValue("150");
        parkParamMapper.updateById(parkParam1);
        try {
            parkCarService.testTrans();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

按照如上的代码:抛出如下异常 Transaction rolled back because it has been marked as rollback-only;数据库中数据也没有被修改。总结一下,spring boot 默认的事物即发生异常无论是否捕获均会回滚。

SUPPORTS: 表示当前方法不需要具有一个事物上下文,当时如果有一个事物的话,它也可以在事物中运行。

A有事物(required)+ B有事物(supports)+ B异常:AB同时回滚。

A有事物(required)+ B有事物(supports)+ B异常 + A捕获:AB同时回滚,抛出Transaction rolled back because it has been marked as rollback-only异常。

MANDATORY(强制性):表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常。

A事物(必须)+ B事物(mandatory):必须同时具备事物。

NESTED(嵌套):表示如果业务A如果有事物,则业务B运行在一个嵌套事物中,被嵌套的事物可以独立于被封装的事物中提交或者回滚,但是如果业务A抛出异常回滚,嵌套事物必须回滚,反之,嵌套事物回滚,业务A不需要回滚。

A无事物 + B(nested) + B异常 :业务A不回滚,业务B回滚。

A无事物 + B(nested)+ A异常 :AB都不回滚。

A有事物 + B(nested) + A异常:AB都回滚。

A有事物 + B(nested)+B异常 : AB都回滚。

A有事物 + B(nested) + B异常 + A捕获 : A不回滚 B回滚。

NEVER(永不): 不运行在事物环境中。

REQUIRES-NEW : 表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

A有事物(required)+ B有事物(requires_new)+ A异常: A回滚,B不受影响。

A有事物(required)+ B有事物(requires_new)+ B异常: AB回滚。

A有事物(required)+ B有事物(requires_new)+ B异常 + A 捕获: A不受影响,B回滚。

NOT_SUPPORT:

A无事物B有事物(not_support)+ B异常:A不回滚,B回滚。

A有事物(required)B有事物(not_support)+ A异常: A回滚,B不回滚。

A有事物(required)try catch,B有事物(not_support)+ B异常:AB都不回滚。

以上就是测试spring boot 事物的传播方式。如果有不对的地方,希望大家指出,开发小白一枚;

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值