本地事务、全局事务、分布式事务

时间:2022-05-02 11:12:53

本地事务、全局事务、分布式事务

本地事务

  1. 事务隔离级别
    select @@tx_isolation
    +—————–+
    | @@tx_isolation |
    +—————–+
    | REPEATABLE-READ |
    +—————–+
    1 row in set (0.00 sec)
  2. 开启事务

线程1执行如下。

use order_db;
begin;
update orders set order_money = order_money + 0.01 where id = 171517987004616228;

线程2执行如下。

select * from orders where id = 171517987004616228;

| id | order_money |
| 171517987004616228 | 94.00 |

线程1执行commit。

commit;

线程2查询。

select * from orders where id = 171517987004616228;

| id | order_money |
| 171517987004616228 | 94.01 |

一次本地事务提交完成,id = 171517987004616228的订单金额增加了0.01。现在假设修改一次订单金额,要修改mysql的订单和oracle的订单金额,这就必须使用全局事务来处理。

全局事务

use order_db;
## 分别开启事务
mysql_connection.begin;
oracle_connection.begin;
## 分别执行操作
update mysql_orders set order_money = order_money + 0.01 where id = 171517987004616228;
update oracle_orders set order_money = order_money + 0.01 where id = 171517987004616228;
## 分别提交,如果有一个失败,则分别进行rollback操作 mysql_connection.commit;
oracle_connection.commit;

全局事务类似于在本地事务基础上做了一层嵌套,实际上多次事务提交和回滚对性能影响较大,占用的资源也比较多。而且全局事务遇到mysql_connection.commit后宕机,尽管oracle_connection提交失败需要回滚,此时已经无法回滚mysql_connection,存在数据不一致的风险。

分布式事务

  1. TCC补偿性事务
    TCC提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm和Cancel三个操作。以支付场景为例,一次支付涉及mysql和oracle的金额变化。
    Try阶段:分别冻结mysql和oracle中的金额。
    Confirm阶段:分别扣除Try阶段中冻结的金额。
    Cancel阶段:分别将冻结金额解冻恢复到用户的余额中。
    由于可能会出现多次提交,需要支持幂等,即同一次请求必须只能成功一次,且每次返回结果都一样。TCC对代码侵入性强,不同的业务场景所写的代码都不一样,复杂度也不一样,代码也不能很好的复用。

  2. 消息队列+最终一致性(最大努力型)
    去哪儿、支付宝也采用过这种方式实现最终一致性。
    利用消息队列+本地事务。如上例,一次支付涉及mysql和oracle的金额变化。
    2.1 执行mysql的本地事务
    2.2 发送消息(消息队列来保证消息发送成功后就不会丢)
    2.1、2.2执行失败就回滚本地事务。当然发送消息成功后如oracle的操作执行失败呢?设置最大重试次数,直到消息的数据处理完成。
    思路就是将分布式事务拆分成多个本地事务,分别来保证每个事务的完整。