1.官方说法

官方的文章中,有这么一段话:

全局事务的隔离性是建立在分支事务的本地隔离级别基础之上的。
在数据库本地隔离级别 读已提交 或以上的前提下,seata 设计了由事务协调器维护的 全局写排他锁,来保证事务间的 写隔离,将全局事务默认定义在 读未提交 的隔离级别上。
我们对隔离级别的共识是:微服务场景产生的分布式事务,绝大部分应用在 读已提交 的隔离级别下工作是没有问题的。而实际上,这当中又有绝大多数的应用场景,实际上工作在 读未提交 的隔离级别下同样没有问题。
在极端场景下,应用如果需要达到全局的 读已提交,seata 也提供了相应的机制来达到目的。默认,seata 是工作在 读未提交 的隔离级别下,保证绝大多数场景的高效性。

2.一个案例

看一下下方这个官方场景案例:
1.有一张表:在这里插入图片描述

2.有两个全局事务分别是tx1,tx2;

3.tx1和tx2都要执行这句sql:UPDATE a SET m = m -10 WHERE id = 1;

2.1正常情况下:

按照时间顺序,tx1和tx2执行了如下操作:
tx1的执行流程如下:

  • 1.tx1 获取local lock;
  • 2.tx1 执行UPDATE a SET m = m -10 WHERE id = 1;但是还未commit;
  • 3.tx1 获取global lock;
  • 4.tx1 local commit;
  • 5.tx1 release local lock;
  • 6.tx1 global commit; 这里标记时间t1;
  • 7.tx1 release global lock;这里标记时间t2;

tx2的执行流程如下:

  • 1.tx2 获取local lock;

  • 2.tx2 执行UPDATE a SET m = m -10 WHERE id = 1;但是还未commit;

  • 3.tx2 要获取global lock;这里标记时间T1;

    tx2为了要local commit,tx2开始去获取global lock;
    我们假设,t1 = T1,说明这个时间节点,两个事务有冲突,此时,全局锁被tx1持有,但是tx2想要local commit前需要先拿到全局锁,幸好,tx1事务进行顺利,在t2释放了全局锁,此时,tx2顺利拿到了全局锁,然后:

  • 4.tx2 获到global lock;

  • 5.tx2 local commit;

  • 6.tx2 release local lock;

  • 7.tx2 global commit;

  • 8.tx2 release global lock;
    在这里插入图片描述

2.2非正常情况下

我们还是用刚才的案例,只是tx1执行过程中,由于tx1这个全局事务中,有其他业务执行失败了,此时决议全局回滚,那么,tx1需要重新获取该数据的本地锁,根据1阶段的回滚日志进行补偿操作,实现a表操作分支的回滚。

那么tx1的执行就成了:

tx1的执行流程如下:

  • 1.tx1 获取local lock;
  • 2.tx1 执行UPDATE a SET m = m -10 WHERE id = 1;但是还未commit;
  • 3.tx1 获取global lock;
  • 4.tx1 local commit;
  • 5.tx1 release local lock;

此时,tx1全局事务上有其他分支事务执行失败,tx1二阶段决议全局回滚。那么,tx1这里,要回滚a表的操作,是要先拿到local lock的;

  • 6.tx1 尝试获取local lock;这里标记时间t1

而tx2的执行流程为:
tx2的执行流程如下:

  • 1.tx2 获取local lock;
  • 2.tx2 执行UPDATE a SET m = m -10 WHERE id = 1;但是还未commit;
  • 3.tx2 要获取global lock;这里标记时间T1;

如果很不巧,t1 = T1,也就是说,在这个尴尬的瞬间:
tx1想要获取这条数据的本地锁,但是本地锁现在被tx2持有;
tx2想要获取这条数据的全局锁,但是全局锁现在被tx1持有。

场景如下:
在这里插入图片描述
这时候会怎样呢?

tx1由于拿不到本地锁,会回滚失败,然后不断的进行重试,而tx2获取全局锁,是有超时时间限制的,一旦获取全局锁超时,tx2会放弃全局锁并回滚本地事务,然后释放本地锁,此时tx1拿到了本地锁,然后回滚成功。

在这个整个过程中,这条数据的全局锁,始终被tx1持有,所以是不会出现脏写的。

未完,待续……

最后更新: 2020年01月16日 17:01

原始链接: https://java4all.cn/2019/10/01/Seata中事务隔离性与锁分析/