返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >Thinkphp6 分布式事务异常处理 1440 XAER_DUPID: The XID already exists
  • 732
分享到

Thinkphp6 分布式事务异常处理 1440 XAER_DUPID: The XID already exists

分布式mysql数据库php 2023-08-31 21:08:53 732人浏览 安东尼
摘要

Mysql分布式事务,前提条件 mysql中只有当隔离级别设置为Serializable的时候才能使用分布式事务。 执行两个命令确认环境 show variables like 'innodb_sup

Mysql分布式事务,前提条件

mysql中只有当隔离级别设置为Serializable的时候才能使用分布式事务。

执行两个命令确认环境

show variables like 'innodb_support_xa';

在这里插入图片描述

show variables like '%tx_iso%';

在这里插入图片描述

异常信息

根据官方分布式示例

public function test()    {        Db::transactionXa(function () {            $updateTime = time();            Db::connect('cdpf_driver')->table('cdpf_driver_user_login_his')->where(["id" => 3128])->update(["login_time" => $updateTime]);            Db::connect('cheduo')->table('users')->where(["id" => 2])->update(["updated_at" => date("Y-m-d H:i:s", $updateTime)]);        }, [Db::connect('cdpf_driver'),Db::connect('cheduo')]);}

如果是同一个服务,执行会出现
异常提示:

sqlSTATE[XAE08]: <>: 1440 XAER_DUPID: The XID already exists

解决办法:

方案一:单独编写,不要用thinkPHP封装好的

public function test()    {        $xid = uniqid('xa');        $updateTime = time();        // 第一个数据库连接        $cdpfDriverXid = "cdpf_driver_{$xid}";        $cdpfDriverDb = Db::connect('cdpf_driver');        $cdpfDriverConnect = $cdpfDriverDb->connect();        // 第二个数据库连接        $cheduoXid = "cheduo_{$xid}";        $cheduoDb = Db::connect('cheduo');        $cheduoConnect = $cheduoDb->connect();        try {            // 第一个事务开始            $cdpfDriverConnect->exec("XA begin '$cdpfDriverXid'");            $cdpfDriverDb->table('cdpf_driver_user_login_his')->where(["id" => 3128])->update(["login_time" => $updateTime]);            $cdpfDriverConnect->exec("XA END '$cdpfDriverXid'");            // 到这里挂起            // 第二个事务开始            $cheduoConnect->exec("XA begin '$cheduoXid'");            $cheduoDb->table('users')->where(["id" => 2])->update(["updated_at" => date("Y-m-d H:i:s", $updateTime)]);            $cheduoConnect->exec("XA END '$cheduoXid'");            // 到这里挂起            // 预执行与提交            $cdpfDriverConnect->exec("XA PREPARE '$cdpfDriverXid'");            $cdpfDriverConnect->exec("XA COMMIT '$cdpfDriverXid'");            $cheduoConnect->exec("XA PREPARE '$cheduoXid'");            $cheduoConnect->exec("XA COMMIT '$cheduoXid'");        } catch (\Exception $ex) {            echo $ex->getMessage();            // 注意:其实如果语句本身存在问题,并没有走到 XA END。这里回滚会抛出异常            $cdpfDriverConnect->exec("XA ROLLBACK '$cdpfDriverXid'");            $cheduoConnect->exec("XA ROLLBACK '$cheduoXid'");        }        return "success";    }

方案二,改动源码

namespace think\db;abstract class PDOConnection extends Connection{    public function transactionXa(callable $callback, array $dbs = [])    {        $xid = uniqid('xa');        if (empty($dbs)) {            $dbs[] = $this;        }        foreach ($dbs as $key => $db) {            if ($db instanceof BaseQuery) {                $db = $db->getConnection();                $dbs[$key] = $db;            }            $db->startTransXa($db->getConfig('hostname').'_'.$db->getConfig('database').'_'.$xid);        }        try {            $result = null;            if (is_callable($callback)) {                $result = $callback($this);            }            foreach ($dbs as $db) {                $db->prepareXa($db->getConfig('hostname').'_'.$db->getConfig('database').'_'.$xid);            }            foreach ($dbs as $db) {                $db->commitXa($db->getConfig('hostname').'_'.$db->getConfig('database').'_'.$xid);            }            return $result;        } catch (\Exception | \Throwable $e) {            foreach ($dbs as $db) {                $db->rollbackXa($db->getConfig('hostname').'_'.$db->getConfig('database').'_'.$xid);            }            throw $e;        }    }}

下面来分析原因:
其实从错误提醒这里很好得知
分布式唯一ID已经存在了

跟踪源码

namespace think\db;abstract class PDOConnection extends Connection{    public function transactionXa(callable $callback, array $dbs = [])    {        $xid = uniqid('xa');        if (empty($dbs)) {            $dbs[] = $this;        }        foreach ($dbs as $key => $db) {            if ($db instanceof BaseQuery) {                $db = $db->getConnection();                $dbs[$key] = $db;            }// 问题就在这里,同一个数据库服务器,一个事务ID还没执行完毕// 又循环生成同样的事务ID,导致异常            $db->startTransXa($xid);        }        try {            $result = null;            if (is_callable($callback)) {                $result = $callback($this);            }            foreach ($dbs as $db) {                $db->prepareXa($xid);            }            foreach ($dbs as $db) {                $db->commitXa($xid);            }            return $result;        } catch (\Exception | \Throwable $e) {            foreach ($dbs as $db) {                $db->rollbackXa($xid);            }            throw $e;        }    }}

来源地址:https://blog.csdn.net/fendouweiqian/article/details/127984862

--结束END--

本文标题: Thinkphp6 分布式事务异常处理 1440 XAER_DUPID: The XID already exists

本文链接: https://www.lsjlt.com/news/387111.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作