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

news2024/11/27 10:32:44

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;

/**
 * 数据库连接基础类
 * @property PDO[] $links
 * @property PDO   $linkID
 * @property PDO   $linkRead
 * @property PDO   $linkWrite
 */
abstract class PDOConnection extends Connection
{
	/**
     * 执行数据库Xa事务
     * @access public
     * @param  callable $callback 数据操作方法回调
     * @param  array    $dbs      多个查询对象或者连接对象
     * @return mixed
     * @throws PDOException
     * @throws \Exception
     * @throws \Throwable
     */
    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;

/**
 * 数据库连接基础类
 * @property PDO[] $links
 * @property PDO   $linkID
 * @property PDO   $linkRead
 * @property PDO   $linkWrite
 */
abstract class PDOConnection extends Connection
{
	/**
     * 执行数据库Xa事务
     * @access public
     * @param  callable $callback 数据操作方法回调
     * @param  array    $dbs      多个查询对象或者连接对象
     * @return mixed
     * @throws PDOException
     * @throws \Exception
     * @throws \Throwable
     */
    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;
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27148.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

input空格回车输入标签

分析 我们自己封装input输入标签需要注意一下几点: 样式实现&#xff0c;span实现标签效果、input隐藏边框(Element-UI可以直接使用tag)。事件监听&#xff0c;确定生成标签的操作&#xff0c;可以是回车,并且需要监听离开焦点的情况。标签限制,最多几个,以及输入验证 html:&…

使用CDC模式改造遗留系统

项目改造背景及挑战 在我们经历的各种遗留系统改造之旅中&#xff0c;使用**绞杀者模式**来改造一个巨大的单体服务&#xff0c;是一种被广泛采用且验证行之有效的手段&#xff0c;在应用传统的绞杀者模式时&#xff0c;通常采用逐步替换的方式&#xff0c;将遗留系统中某一独…

b站pink老师JavaScript的ES6面向对象课程中:正则表达式案例代码——表单验证

目标效果&#xff1a; 1.当输入的手机号&#xff0c;QQ号&#xff0c;昵称&#xff0c;短信验证码&#xff0c;登录密码&#xff0c;确认密码&#xff1a;如果符合标准&#xff0c;就提示正确的文字;如不符合标准&#xff0c;则提示不正确。 2.判断确认密码是否与登录密码相等…

落实交通强国,鄂州临空区联手蘑菇车联打造新时代内陆开放高地

临空经济与智能网联、自动驾驶能擦出什么样的火花&#xff1f;今年7月&#xff0c;鄂州花湖机场投运&#xff0c;标志着这个湖北省“一号工程”正式蝶变为亚洲规模最大、自动化程度行业领先的航空货运枢纽。鄂州花湖机场项目也是湖北加快建设交通强国示范区、打造新时代“祖国立…

Spring Boot配置多个日志文件记录不同类日志示例

了解如何使用多个文件追加器在Spring 引导应用程序中创建多个日志文件。了解如何使用翻转策略、归档等配置所有文件追加器&#xff0c;wiihlog4j2和日志配置。 1. 带登录的多个日志文件 以下文件包含 5 个记录器。我们可以根据需要创建更多的记录器。logback.xml console– …

NeRF源码运行与学习(pytorch)

神经辐射场&#xff08;NeRF&#xff09;是一个简单的全连接网络&#xff08;权重约为5MB&#xff09;&#xff0c;经过训练&#xff0c;可以使用渲染损失再现单个场景的输入视图。网络直接从空间位置和观看方向&#xff08;5D输入&#xff09;映射到颜色和不透明度&#xff08…

翻译文本的软件有哪些?这几个翻译工具你可以试试看

文本翻译&#xff0c;是我们在生活中或工作中比较常见的一个需求。例如有时收到一份英文资料&#xff0c;没时间逐字翻译成中文&#xff0c;那就需要借助翻译工具来帮忙了&#xff1b;或者是有时需要将一些内容翻译成英文&#xff0c;而碰巧遇到句子不知道如何翻译&#xff0c;…

DDPM(Denoising Diffusion Probabilistic Models)扩散模型简述

引言 扩散模型最早是在2015年的Deep Unsupervised Learning using Nonequilibrium Thermodynamics文章中提出的&#xff0c;但当时扩散模型并不work&#xff0c;所以并没有被广泛应用。在2020年&#xff0c;Denoising Diffusion Probabilistic Models(简称为DDPM)的出现&#…

[附源码]java毕业设计校园闲置物品交易

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MCE | 动物实验溶剂大讨论

在动物实验中&#xff0c;药物通常会以溶液 (Solution) 或混悬液 (Suspension) 的形式给药。我们需选择合适的溶剂&#xff0c;可以辅助超声加热措施&#xff0c;得到澄清的溶液或适合给药的混悬液。■ 人见人爱的生理盐水/PBS 对于水溶性很好的产品&#xff0c;用生理盐水 (Sa…

中学数学课程标准(教学大纲)的传承与变迁

目 录 摘 要 I Abstract II 第一章 绪论 1 1.1研究背景及意义 1 1.2研究现状 1 1.3研究内容 3 第二章 1990以来我国中学数学课程标准&#xff08;教学大纲&#xff09;改革回顾 4 2.1改革回顾 4 2.1.1 1990年数学教学改革的内容 4 2.1.2 2001年数学教学改革的内容 5 2.1.3 2011…

XSS(Cross-site Script,跨站脚本)漏洞笔记

起源 最早的 XSS 漏洞可追溯到 1999 年末&#xff0c;微软安全工程师发现一些网站遭到攻击&#xff0c;网站被插入了一些恶意脚本和图像标签。随后&#xff0c;微软对此类漏洞进行研究分析&#xff0c;并在 2000 年 1 月&#xff0c;正式使用“cross-site scripting”这个名称…

C语言-指针初阶(6)

目录 思维导图&#xff1a; 1. 指针是什么&#xff1f; 2. 指针和指针类型 2.1 指针-整数 2.2 指针的解引用 3. 野指针 3.1 野指针成因 3.2 如何规避野指针 4. 指针运算 4.1 指针-整数 4.2 指针-指针 4.3 指针的关系运算 5. 指针和数组 6. 二级指针 7. 指针数组…

50行Python代码实现自动下载小说,并打包exe直接

前言 室友喊着没有小说看&#xff0c;让我给他推荐几本&#xff0c;这能难倒我&#xff1f; 分分钟就用python给他把整个网站的小说都给下载下来了&#xff0c;不愧是我啊&#xff01; 话不多说&#xff0c;我们直接开整&#xff01; &#xff08;文末送读者福利&#xff09…

python之爬虫的学习

python爬虫入门-1为什么要学习爬虫浏览器背后的秘密常用网络请求URL解析HTTP常见响应状态码相关库及其简单使用相关引用综合栗子为什么要学习爬虫 现如今&#xff0c;浏览器可以更方便的进行网页交互以人们适合阅读的方式展示数据&#xff1b;但爬虫或者网页抓取对数据的收集和…

第5章 输入/输出(I/O)管理

5.1 I/O管理概述 5.1.1 I/O设备 I/O设备的分类&#xff08;按使用特性分类&#xff09;I/O设备的分类&#xff08;按传输速率分类&#xff09;I/O设备的分类&#xff08;按信息交换的单位分类&#xff09; 5.1.2 I/O控制方式 有4种&#xff1a; 1. 程序直接控制方式2. 中…

都是同样条件的mysql select语句,为什么读到的内容却不一样?

假设当前数据库里有下面这张表。 老规矩&#xff0c;以下内容还是默认发生在innodb引擎的可重复读隔离级别下。 大家可以看到&#xff0c;线程1&#xff0c;同样都是读 age > 3 的数据。第一次读到1条数据&#xff0c;这个是原始状态。这之后线程2将id2的age字段也改成了3。…

kubelet源码 删除pod(二)

kubelet源码 删除pod&#xff08;二&#xff09; 本文中含有k8s的一个bug&#xff0c;我也正在努力提交PR&#xff0c;不过会不会被merge就不清楚了。 kubernetes PR地址 pod_workers.go是主要处理pod变化的文件&#xff0c;在1.22版本后对这个文件进行了比较大的修改。把属…

[附源码]SSM计算机毕业设计基于SSM的酒店管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

QT 字符串操作常用接口函数

目录常见字符串处理函数空白字符串处理函数查询字符串数据字符串比较字符串的转换QT版本的STLQLinkedList和QVector的区别QT提供的STL命名风格的迭代器QMap和QHash经过该简单设置可以防止msvc环境下使用qdebug打印输出时出现中文乱码的问题。 #include "learn.h" #i…