事务的传播级别和隔离级别

事务是在我们日常开发中经常会用到的知识,比如事务的特性(原子性,一致性,持久性,隔离性)、事务的隔离级别、事务的传播级别等等

事务的隔离级别

Spring的事务隔离级别有四个:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE,还有一个,是数据库默认的隔离级别DEFAULT,MySQL默认是REPEATABLE_READ

这里解释下上面提到的几种异常:

(1)脏读:读到了其他事务还没有提交的数据。

(2)不可重复读:对某数据进行读取,发现两次读取的结果不同,也就是说没有读到相同的内容。这是因为有其他事务对这个数据同时进行了修改或删除。

(3)幻读:事务 A 根据条件查询得到了 N 条数据,但此时事务 B 更改或者增加了 M 条符合事务 A 查询条件的数据,这样当事务 A 再次进行查询的时候发现会有 N+M 条数据,产生了幻读。

事务的传播级别

事务有七个传播级别:
1.PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
2.PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
3.PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4.PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5.PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
6.PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
7.PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

其中常用的PROPAGATION_REQUIRED能够覆盖大多数业务场景,其他的知道就行,也很好理解

事务不生效的原因
1.异常被捕获 没有进行抛出
2.抛出非运行时异常(可以指定回滚类型为exception),因为事务指定的默认异常是运行时异常
3.注解在非public方法上面
4.方法内部非事务调用事务方法
(自己注入自己,在非事务方法当中通过注入的自己的对象调用事务方法)
5.开启一个新的线程
6.数据库本身不支持,事务的传播属性设置为不支持事务(当前事务被挂起)

分布式事务解决方案

Seata 是一款开源的分布式事务解决方案,Seata 提供了 AT、TCC、SAGA 和 XA 事务模式

1、AT模式主要关注多 DB 访问的数据一致性,当然也包括多服务下的多 DB 数据访问一致性 问题
2、TCC模式主要关注业务拆分,在按照业务横向扩展资源时,解决间调用的一致性问题

AT模式
AT 模式是 Seata 主推的分布式事务解决方案,对业务无侵入,真正做到了业务与事务分离,用户只需关注自己的“业务 SQL语句”。
AT模式使用起来非常简单,与完全没有使用分布式事务方案相比,业务逻辑不需要修改,只需要增加一个事务注解@GlobalTransactional即可


TCC模式
TCC 模式需要用户根据自己的业务场景实现 try()、confirm() 和 cancel()这3个方法:事务发起方在一阶段执行try()方法,在二阶段提交执行 confirm()方法,在二阶段回滚执行cancel()方法

TCC 模式与AT模式的主要区别如下。
(1)在使用上,TCC 模式依赖用户自行实现的3个方法(try()、confirm()、cancel())成本较大;AT 模式依赖全局事务注解和代理数据源,代码基本不需要改动,对业务无侵入、接入成本极低。
(2)TCC 模式的作用范围在应用层,本质上是实现针对某种业务逻辑的正向和反向方法;AT模式的作用范围在底层数据源,通过保存操作行记录的前、后镜像和生成反向SQL语句进行补偿操作,对上层应用透明。
(3)TCC模式事务并发控制由业务自行“加锁”,AT模式由Seata框架自动“加锁”
1.举例
以“扣钱”场景为例,在接入 TCC 模式前,对账户“扣钱”,只需一条更新账户余额的 SQL 语句就能完成;但是在接入 TCC 模式之后,用户则需要考虑如何将原来一步就能完成的“扣钱”操作拆成两阶段,实现成3个方法,并且保证如果一阶段try()方法成功则二阶段 confirm()方法也一定能成功。
如下图所示,try()方法在一阶段执行,需要做资源的检查和预留。在“扣钱”场景下,try()方法要做的是检查账户余额是否充足、预留转账资金(预留的方式就是冻结A账户的转账金额)。在try()方法执行后,账户A的余额虽然还是100元,但是其中有30元已经被冻结了,不能被其他事务使用。
二阶段confirm()方法执行真正的“扣钱”操作。confirm()方法会使用try()方法冻结的金额执行账号“扣钱”。在confirm()方法执行后,账户 A 在一阶段中冻结的 30 元已经被扣除,账户 A 的余额变为 70 元 。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值