基于DTM分布式事务管理的PHP客户端

DTM是一套跨语言的分布式事务解决方案,支持4种事务模型(Xa、Tcc、事务消息、Saga),针对分布式事务场景中可能出现的空回滚、悬挂问题,独创了子事务屏障,在大厂均有应用,但已有的php客户端只支持tcc,所以重新开发了这个组件。

一、启动本地dtm

DTM文档教程

git clone https://github.com/yedf/dtm && cd dtm
go mod download
go run app/main.go dtmsvr
二、安装客户端

composer require sett/dtmcli-php

三、示例代码
  • tcc
    特性:一个操作对应2段提交,预处理(try),确认(confirm)、回滚(cancel),确认与回滚不允许失败。

    // 127.0.0.1:36789为dtm默认端口
    $trans   = new TccTrans("127.0.0.1:36789");
    // 获取新事务ID
    $gid     = $trans->createNewGid();
    // 事务操作 
    $success = $trans->withOperate($gid, function (TccTrans $tccTrans) use ($baseUrl) {
        $result = $tccTrans->callBranch(
            ["amount" => 30],
            "$baseUrl/dtm/tcc/transOut",
            "$baseUrl/dtm/tcc/transOutConfirm",
            "$baseUrl/dtm/tcc/transOutCancel"
        );
        if (!$result) {
            echo "call branch fail\n";
            return false;
        }
        return $tccTrans->callBranch(
            ["amount" => 30],
            "$baseUrl/dtm/tcc/transIn",
            "$baseUrl/dtm/tcc/transInConfirm",
            "$baseUrl/dtm/tcc/transInCancel"
        );
    });
  • saga
    特性:一个操作对应1个回滚,任何一个失败,整个事务视为失败,回滚。

    $trans = new SagaTrans("127.0.0.1:36789");
    $gid   = $trans->createNewGid();
    $trans
        ->withGid($gid)
        ->withOperate("$baseUrl/dtm/saga/transOut", "$baseUrl/dtm/saga/transOutRevert", ["amount" => 30])
        ->withOperate("$baseUrl/dtm/saga/transIn", "$baseUrl/dtm/saga/transInRevert", ["amount" => 30]);
    $success = $trans->submit();
  • 事务消息
    特性:操作对应一个查询。

    $trans = new MsgTrans("127.0.0.1:36789");
    $gid   = $trans->createNewGid();
    $trans
        ->withOperate("$baseUrl/dtm/msg/transOut", ["amount" => 30])
        ->withOperate("$baseUrl/dtm/msg/transIn", ["amount" => 30])
        ->withQueryUrl("$baseUrl/dtm/msg/query")
        ->prepare();
    $success = $trans->submit();
  • 子事务屏障
    特性:防止空回滚,处理悬挂,幂等等问题。

    class UserDatabase implements IDatabase
     {

      public function execute(string $query) {
          // TODO: Implement execute() method.
      }

      public function query(string $query): bool {
          // TODO: Implement query() method.
      }

      public function rollback() {
          // TODO: Implement rollback() method.
      }

      public function commit() {
          // TODO: Implement commit() method.
      }
     }

    $baseUrl = "http://127.0.0.1:18310";
    try {
        $trans    = new BarrierTrans([
        "trans_type" => "tcc",
        "gid"        => "ac130059_4pQHea5Xtsq",
        "op"         => "prepare",
        "branch_id"  => "01"
        ]);
        $database = new UserDatabase();
        $success  = $trans->call($database, function (IDatabase $database) {
           // 使用当前数据库连接操作,保证所有操作都在一个本地事务中
           // do what you want...
           return true;
        });
        echo "transaction result {$success}";
    } catch (Exception $exception) {
        var_dump($exception->getTraceAsString());
        echo "exception with error " . $exception->getMessage();
    }
  • Xa
    特性:基于数据库本地事务,保证操作在同一个事务中,使用的场景比较少,不写了

本作品采用《CC 协议》,转载必须注明作者和本文链接
失色天空
本帖由系统于 2年前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 10

saga 这样 是不是会有脏读的概率 如果在 transIn 后 用户马上查询 其实是transIn后的数据, 然后这个时候commit 失败嘞

6个月前 评论
失色天空 (楼主) 6个月前

问个问题, saga模式怎么定义 正向操作是失败 需要回滚 dtm 怎么判断是http状态码 还是业务状态来实现 回滚 或者是重试操作呢??

5个月前 评论
Smilephp (作者) 5个月前
Smilephp (作者) 5个月前
失色天空 (楼主) 5个月前
Smilephp (作者) 5个月前
Smilephp (作者) 5个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!