一文带你彻底搞懂Spring事务传播机制

日日行,不怕千万里

什么是Spring的事务传播机制?项目中遇到长事务怎么处理?相信这是大多数人面试时会被问到的高频问题,那今天就来聊聊这个问题。

事务

什么是事务?

事务这个词大家都不会陌生,甚至ACID背的滚瓜烂熟,被问到这个,心里一喜,心想这不是手到擒来吗?直接撞咱枪口上了。

接下来你了你的表演:

  • 事务的特性

    • 原子性:一个事务中的所有操作,要么全部成功,要么全部失败,没有中间状态。

    • 一致性:事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态,这是事务追求的最终状态,可以说其他的三个特性都是为了保证事务的一致性。

    • 隔离性:事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰,严格的隔离性对应了串行化执行,但是实际操作中很少会用到串行化的隔离级别,一般来说可以分两个方面来保证隔离性。

      • A事务写对B事务写的影响:通过锁来保证
      • A事务写对B事务读的影响:通过MVCC来保证
    • 持久性:事务一旦提交,对数据库的影响应该是永久性的。

那你平时在项目中是如何使用到事务的?

哎呀,那这不又是正中下怀吗?

首先,Spring对事务的支持建立在你所使用的数据库,如果你使用的是mysql数据库,恰好又是使用的innodb引擎,那么恭喜你,是支持事务的。那Spring对事物的支持一般有两种方式:

public class Test1 {
    @Autowired
    private TransactionTemplate transactionTemplate;
    public void testProgrammingTransaction() {
​
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                try {
                    // ....  do something
                } catch (Exception e){
                    //rollback
                    transactionStatus.setRollbackOnly();
                }
​
            }
        });
    }
}
  • 声明式事务管理:使用场景最多,也是最推荐使用的方式,直接加上@Transactional注解即可。

那你项目中遇到长事务是如何处理的呢,如果有一百个操作,怎么处理这种事务呢?

事务嵌套是如何处理的呢?再比如A事务中嵌套了B事务,B事务成功开启了吗?

完了完了,你开始支支吾吾,面试官看你回答不上来,问了几个无关紧要的问题,然后心不在焉的问你有什么要问他的,你知道,凉了,要回去等通知了...

Spring事务传播机制

你回去仔细研究了一下发现,事务传播机制一共有七种:

PROPAGATION_REQUIRED:Spring的默认传播级别,如果上下文中存在事务则加入当前事务,如果不存在事务则新建事务执行。

PROPAGATION_SUPPORTS:如果上下文中存在事务则加入当前事务,如果没有事务则以非事务方式执行。

PROPAGATION_MANDATORY:该传播级别要求上下文中必须存在事务,否则抛出异常。

PROPAGATION_REQUIRES_NEW:每次执行都会创建新事务,并同时将上下文中的事务挂起,执行完当前线程后再恢复上下文中事务。

PROPAGATION_NOT_SUPPORTED:当上下文中有事务则挂起当前事务,执行完当前逻辑后再恢复上下文事务。

PROPAGATION_NEVER:该传播级别要求上下文中不能存在事务,否则抛出异常。

PROPAGATION_NESTED:嵌套事务,如果上下文中存在事务则嵌套执行,如果不存在则新建事务

哦豁,已看完这个,已经更晕了,于是你下定决心一定要搞懂,不然下次面试又得嗝屁。你去翻了翻网上大神的文章,又问了问身边的同事大佬,大佬告诉你,这七个中,你只需要记住其中两个就能应付大多数的问题,这里的大多数是大于等于90%。

  • PROPAGATION_REQUIRED:Spring默认传播级别当然不用多说,那如何理解上下文中如果存在事务,就加入当前事务呢,如果不存在就新建事务执行呢?

    • 如果A事务中如果嵌套了B事务,B事务也不会是单独的,也会加入到A事务中。
    • 如果A事务失败,回滚。
    • 如果A事务中,B事务开始前的前置操作执行成功,事务不会提交,继续执行B事务。
    • 如果B事务失败,因为B事务是加入了当前事务(上下文中的事务,A事务),连同A事务一起回滚

    在下面代码中,a不可以正常插入数据库,会造成回滚。原因在于使用的Spring默认的事务传播机制,Test1的事务会加入到Test的事务中。

    public class Test {
        @Autowired
        private static Test1 test1;
        @Autowired
        private static AMapper aMapper;
        @Transactional
        public void testTransaction(A a) throws Exception {
            aMapper.insert(a);
            try {
                test1.required();
            }catch (Exception e){
                System.out.println(e);
            }
        }
    }
    
    public class Test1 {
        @Transactional
        public void required() {
            throw new NullPointerException("throw a test exception");
        }
    }
  • PROPAGATION_REQUIRES_NEW:每次执行都会创建新事务,并同时将上下文中的事务挂起,执行完当前线程后再恢复上下文中事务,这句话应该比较好理解了,可以理解为事务是单独的,嵌套的事务不会影响上下文中的事务。

    • 如果A事务中嵌套了B事务,B事务会是单独执行的,此过程中A事务会暂时挂起。
    • 如果B事务执行成功,B事务提交,A事务恢复。
    • 如果B事务执行失败,B事务回滚,A事务恢复。
    • B对于A来说是单独的,B事务的失败不会造成A事务的失败,当然是在有try-catch的情况下。
    • 如果没有try-catch或者说A事务直接执行失败了,不用想,数据是肯定会插入失败的。

    就像下面的代码一样,有try-catch,a可以插入成功,如果没有try-catch,a一定会插入失败。

    public class Test {
        @Autowired
        private static Test1 test1;
        @Autowired
        private static AMapper aMapper;
        @Transactional
        public void testTransaction(A a) throws Exception {
            aMapper.insert(a);
            try {
                test1.required();
            }catch (Exception e){
                System.out.println(e);
            }
        }
    }
    public class Test1 {
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void required() {
            throw new NullPointerException("throw a test exception");
        }
    }
    

其他情况

那么如果遇到其他情况,乖乖的来看你需要的是哪种Spring事务传播机制吧。

另:@Transactional默认情况下,只回滚RuntimeException哦。

后记

你不可能真想把这玩意全背下来吧,退一万步讲,就算你全背下来了,面试官会不知道你是背的?

面试官内心OS:这能全知道?肯定这小子是个卷王,八股文背的这么溜,要是招进来,还不得把我也卷出去?
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值