AT

事务的隔离级别

  • 读未提交: 可以读取还没有提交的事务产生的数据,这就是脏读的产生原因
  • 读已提交:读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行 ,解决了脏读问题,但是可能产生重复读
  • 可重复读:读取数据的事务将会禁止写事务,写事务则禁止任何其他事务,但任然可能产生幻读,当前数据库默认隔离基本
  • 串行化:提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行,解决了幻读的问题

脏写

业务一开启全局事务,其中包含分支事务A(修改 A)和分支事务 B(修改 B),业务二修改 A, 其中业务一执行分支事务 A 先获取本地锁,业务二则等待业务一执行完分支事务 A 之后,获得本地锁修改 A 并入库, 业务一在执行分支事务时发生异常了,由于分支事务 A 的数据被业务二修改,导致业务一的全局事务无法回滚。

一旦发生脏写,TC就会不断重试去回滚,但是他永远不会成功,就是一个死循环,哪怕重启应用程序都不行, 有一个解决办法就行吧数据恢复到事务A修改后的状态

如何防止脏写?

  1. 业务二执行时加 @GlobalTransactional注解
  2. 业务二执行时加 @GlobalLock注解

脏读

全局事务未提交前,被其它业务读到已提交的分支事务的数据

如何防止脏读

业务二查询 A 时加 @GlobalLock 注解 + select for update语句

question
  • 一个业务开启全局事务,其中包含分支事务A(修改 A表)和分支事务 B(修改 A表)会造成分支事务 B无法获取锁吗? 不会
  • 一个业务开启全局事务,其中包含分支事务A 和分支事务 B,在执行分支事务 B前B断网会怎么样? Feign调用 B 失败,全局回滚
  • 一个业务开启全局事务,其中包含分支事务A 和分支事务 B,在执行分支事务 B在执行中时 B 断网会怎么样? 会回滚,且事务 B的修改也会回滚
  • 一个业务 T 开启全局事务,其中包含分支事务A 和分支事务 B,在执行分支事务 B在执行中时 T 断网会怎么样? TC会尝试叫 T 服务的 RM 去回滚事务,但是 T 掉线,无法回滚成功,TC进入死循环,直到 T 上线
  • 一个业务开启全局事务,其中包含分支事务A 和分支事务 B,在调用分支事务 B时使用子线程去调用会怎么样? 分支事务 B无法参与全局事务,如果B 有全局锁会获取不到全局锁,返回调用失败,事务 A回滚, 如果 B没有全局锁则当全局事务回滚时事务 B不会参与回滚
  • 当分支事务A 执行成功,然后在执行分支事务B 时TC断网或宕机,这个全局事务会怎么样? 分支事务B 会执行, 但是无法提交事务且各服务会重新尝试连接TC,当TC上线后无论全局事务是否超时都会全局回滚

TCC

TCC Feign 远程调用其他服务参与者的 Try 方法的时候不能放在子线程下,否则全局事务不生效

空回滚

  1. 空回滚指的是在一个分布式事务中,在没有调用参与方的 Try 方法的情况下,TM 驱动二阶段回滚调用了参与方的 Cancel 方法。

  2. 参与者 A 一阶段方法未成功执行,但是此时全局事务已经开启,在全局事务回滚时会调用参与者 A 的 Cancel 方法,从而造成空回滚。

  3. 如果是网络异常导致参与者 A没有开始进入一阶段方法,直到TC调用二阶段取消,则seata不会造成空回滚。 但是一旦在调用参与者 A 一阶段方法后,由于各种原因造成一阶段没有执行成功,则在seata 1.3.0中会造成空回滚,需要开发者自己设计

幂等

  1. 幂等问题指的是 TC 重复进行二阶段提交,因此 Confirm/Cancel 接口需要支持幂等处理, 即不会产生资源重复提交或者重复释放。

  2. 参与者 A 执行完二阶段之后,由于网络抖动或者宕机问题,会造成 TC 收不到参与者 A 执行二阶段的返回结果, TC 会重复发起调用,直到二阶段执行结果成功。

  3. seata 1.3.0中需要开发者自己设计幂等,防止重复提交

悬挂

SAGA