Mysql分布式事务,前提条件 mysql中只有当隔离级别设置为Serializable的时候才能使用分布式事务。 执行两个命令确认环境 show variables like 'innodb_sup
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
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
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0