Spring 事务,你真的用对了吗 (下篇)?

在上一篇关于事务的文章中,我们遗留了一个问题,@Transactional 注解中的参数 Propagation = Propagation.REQUIRED 是什么?今天我们就来揭开谜底。
这个东西可厉害了, 他是 Spring 为我们提供的事务传播机制,帮我们完成各种业务需求。比如依旧是两个 service 方法。我们想让外部的方法异常回滚,内部方法的操作不回滚, 上一篇中提到的方法就无法满足了。别急,学完了今天的内容, 你就能运用自如了, 各种事务问题也都难不倒你了。
首先,让我们来看一下 Spring 都为我们提供了哪几种事务的传播机制,他们的作用都是什么, 我简单罗列如下:

那每一个传播机制都有什么样的特点呢, 我们依旧通过代码实验来学习。
Propagation.REQUIRED(默认)
外部事务和内部事务是一个事务, 所有是一荣俱荣,一损俱损, 即内部回滚会导致外部回滚, 外部回滚也会导致内部回滚, 不滚外部是否 catch 住了内部方法的异常。
未 catch 内部方法异常


结果: 两条记录都没有插入成功
catch 内部方法的异常


结果: 两条记录都没有插入成功
外部方法抛出异常


结果: 两条记录都没有插入成功
Propagation.REQUIRED_NEW
外部和内部不是同一个事务,内部事务和外部事务是相互独立的, 可以互相不影响。前提是不能让外部事务感知到异常。
未 catch 住内部方法异常


结果: 两条记录都没有插入成功
catch 住内部方法异常


外部方法抛出异常

结果: 外部方法记录插入失败, 内部方法第一条记录成功
Propagation.NESTED
内部事务是外围事务的子事务,如果外部事务回滚,子事务一定回滚,但子事务可以单独回滚, 而不影响外部事务,前提是不能让外部事务感知到异常。
未 catch 住内部方法异常


结果: 两条记录都没有插入成功
catch 住内部方法异常


结果: 第一条记录成功插入, 第二条记录失败
外部方法抛出异常


结果: 两条记录都没有插入成功
前面讲解的都是我们平时开发时会用到的, 还有一种是 Propagation.NOT_SUPPORTED,这种是以非事务的方式运行, 所以不管内部还是外部方法抛出异常, 都不会回滚方法本身。其余几种少用到, 大家就自己动手做做实验学习一下吧。
总结
综合上一篇的内容, 我们可以看出 Spring 事务真的可以解决我们业务需求的大部分场景。在我们需要事务时,直接使用 @Transactional 注解就好。当我们的事务跨了多个 service 时,就要考虑我们期望它们的行为是什么,是同一个事务,还是各自独立的事务,是内部不使用事务,还是外部不使用事务。分析完需求再选择合适的事务传播机制就好啦。

版权声明: 本文为 InfoQ 作者【废材姑娘】的原创文章。
原文链接:【http://xie.infoq.cn/article/b720947f3b79a81e5e5ceda77】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论