• 简单聊聊事务补偿机制


    假设有如下的业务流程,用户1给用户2转账100元:

     转账服务需要执行如下操作:

    第1步. 在数据库连接1上执行:update 用户表 set (用户1的余额) = (用户1的余额)- 100;

    第2步. 在数据库连接2上执行:update 用户表 set (用户2的余额) = (用户2的余额)+ 100;

    可能的问题:

    1:第1步操作过程中,数据库1挂了,转账服务无法得知对用户1的扣款操作是否成功;

    2:第1步操作成功,第2步操作失败,转账服务回滚第1步的操作时,数据库1挂了;

    3:第1步操作成功,第2步操作过程中,数据库2挂了,转账服务无法得知是否成功给用户2加了钱;

    基于上面的问题,产生了如下的数据库设计:

    转账流程变成了如下步骤:

    第1步:

        转账服务生成一个事务号,全局唯一;

    第2步:转账服务在数据库1上执行事务:

        开始事务:

            update 用户表 set (用户1的余额) = (用户1的余额)- 100;

            insert 事务表 (事务号,成功)

        结束事务:

    第3步:转账服务在数据库2上执行事务:

        开始事务:

            update 用户表 set (用户2的余额) = (用户2的余额)+ 100;

            insert 事务表 (事务号,成功)

        结束事务:

    这样做的好处

        当操作用户1的账户失败时,转账服务可以通过再次查询数据库1的事务表来判断操作是否成功;

        当操作用户2的账户失败时,转账服务可以通过再次查询数据库2的事务表来判断操作是否成功;

    接下来的问题:

        当转账服务更新用户1的账户成功后,接下来转账服务更新用户2的账户之前,转账服务自己挂了;

        这时,用户1被扣了100,但是用户2没多出来100,数据不一致;

    新的数据库设计产生了,如下:

        

    接下来的操作步骤变成了这样:

    转账服务的操作:

        第1步:生成全局唯一事务号;生成事务号对应的时间戳;

        第2步:在回滚库的日志表中插入---“事务号开始”的操作;

        第3步:在回滚库的日志表插入---“扣除用户1的账户100元“的操作;

        第4步:在数据库1上执行事务:

            开始事务:

                update 用户表 set (用户1的余额) = (用户1的余额)- 100;

                insert 事务表 (事务号,成功)

            结束事务:

        第5步:在回滚库的日志表插入---“增加用户2的账户100元”的操作;

        第6步:在数据库2上执行事务:

            开始事务:

                update 用户表 set (用户2的余额) = (用户2的余额)+ 100;

                insert 事务表 (事务号,成功)

            结束事务:


        第7步:在回滚库的日志表插入---“事务号结束”的操作;

    回滚服务的操作:

        假设转账超时时间是1小时;

        定期检查回滚库中的回滚日志表;

        如果事务号对应结束,则忽略;

        如果事务号没有结束,但是事务没超时,也忽略;

        如果事务号没有结束,事务超时,则按照回滚日志,反向操作,对事务进行补偿,补偿步骤如下:

            第1步:对用户2进行事务补偿,检查数据库2的用户2的事务是否成功;

            第2步:如果成功,则认为事务完成,在事务回滚日志表中将这次事务标识为成功;并跳到“结束步骤”;

            第3步:对用户1进行事务补偿,检查数据库1的用户1的事务是否成功;

            第4步:如果成功,则执行如下事务:

                开始事务

                    update 用户表 set (用户1的余额) = (用户1的余额)+ 100;

                    update 事务表 (事务号,回滚成功);

                结束事务

            第5步:在事务回滚日志表将这次事务标识为成功;

            结束步骤

     结束哈;

  • 相关阅读:
    Python iter() 函数
    Python file() 函数
    Python bin() 函数
    QTP自动化测试-打开运行报告
    mysql-笔记-数据类型
    mysql-笔记--增删改查
    mysql-笔记-命名、索引规范
    Navicat for MySQL 安装和破解
    mysql client--笔记-修改密码-登录-查看数据库-创建数据库
    安装mysql
  • 原文地址:https://www.cnblogs.com/lijingshanxi/p/9943836.html
Copyright © 2020-2023  润新知