php处理跨服务器事务

事务只用过最简单的:同个数据库不同表之间的事务。最近遇到了跨DB server的事务,记录下。

同个DB server上的不同数据库的单个事务

<?php

function getConn($ip, $port, $dbbane, $user, $password)
{
    $dsn = "mysql:host=$ip;port=$port;dbname=$dbbane;charset=utf8";
    $mysqli = new PDO($dsn, $user, $password);
    return $mysqli;
}


try {
    $mysqli = getConn('127.0.0.1', '3306', 'test', 'root', '');

    $mysqli->beginTransaction();

    $num1 = 0;
    $num2 = 0;
    try {
        $name = 'test' . rand(1, 999);
        $age = rand(1, 99);
        $dt = date('Y-m-d H:i:s');
        $sql = "INSERT into test.test_table (`name`,`age`,`create_time`) values ('$name',$age,'$dt');";
        $res = $mysqli->query($sql);
        $num1 = $res->rowCount();
        // $num1 = 0;

        $sql = "INSERT into test2.test_table (`name`,`age`,`create_time`)) values ('$name',$age,'$dt');";
        $res = $mysqli->query($sql);
        $num2 = $res->rowCount();
        // $num2 = 0;

        if ($num1 > 0 && $num2 > 0) {
            $mysqli->commit();

            echo 'COMMIT';
        } else {
            $mysqli->rollBack();

            echo 'ROLLBACK';
        }
    } catch (Exception $e) {
        $mysqli->rollBack();

        var_dump($e->getMessage());
    }
} catch (Exception $e) {
    var_dump($e->getMessage());
}
unset($mysqli);

可以正常提交或者回滚,数据记录正常,回滚的事务在DB中会造成实际记录自增id跳过的情况。

XA分布式事务

根据资料显示:只有Innodb引擎且设置隔离级别为可串行化时才可以使用XA事务,然而下面简单demo中隔离级别为可重复读,事务可以正常提交或回滚,数据记录正常。

<?php

function getPdoInfo($mysqli)
{
    $result = $mysqli->query("SELECT VERSION()");
    $row1 = $result->fetch();
    $version = $row1[0];

    $result = $mysqli->query("SELECT @@GLOBAL.TX_ISOLATION;");
    // $result = $mysqli->query("SELECT @@GLOBAL.TRANSACTION_ISOLATION;");
    $row2 = $result->fetch();
    $isolation = $row2[0];
    return compact('version', 'isolation');
}

function getConn($ip, $port, $dbbane, $user, $password)
{
    $dsn = "mysql:host=$ip;port=$port;dbname=$dbbane;charset=utf8";
    $mysqli = new PDO($dsn, $user, $password);
    return $mysqli;
}

try {
    $mysqli1 = getConn('127.0.0.1', '3306', 'test', 'root', '');
    $mysqli2 = getConn('192.168.12.12', '3306', 'test2', 'root', '');

    // var_dump(getPdoInfo($mysqli1));
    // var_dump(getPdoInfo($mysqli2));

    $xid = uniqid();
    $sql = "XA START '$xid'";
    $res = $mysqli1->query($sql);
    $res = $mysqli2->query($sql);

    $num1 = 0;
    try {
        $name = 'test' . rand(1, 999);
        $age = rand(1, 99);
        $dt = date('Y-m-d H:i:s');
        $sql = "INSERT into test.test_table (`name`,`age`,`create_time`) values ('$name',$age,'$dt');";
        $res = $mysqli1->query($sql);
        $num1 = $res->rowCount();
        // $num1 = 0;

        $sql = "INSERT into test2.test_table (`name`,`age`,`create_time`)) values ('$name',$age,'$dt');";
        $res = $mysqli2->query($sql);
        $num2 = $res->rowCount();
        // $num2 = 0;
    } catch (Exception $e) {
        var_dump($e->getMessage());
    }

    $sql = "XA END '$xid'";
    $mysqli1->query($sql);
    $mysqli2->query($sql);

    if ($num1 > 0 && $num2 > 0) {
        $sql = "XA PREPARE '$xid'";
        $mysqli1->query($sql);
        $mysqli2->query($sql);

        $sql = "XA COMMIT '$xid'";
        $mysqli1->query($sql);
        $mysqli2->query($sql);

        echo 'COMMIT';
    } else {
        $sql = "XA ROLLBACK '$xid'";
        $mysqli1->query($sql);
        $mysqli2->query($sql);

        echo 'ROLLBACK';
    }
} catch (Exception $e) {
    var_dump($e->getMessage());
}
unset($mysqli);

多个事务同时操作

突发奇想试了下多个事务同时提交或者回滚,事务可以正常提交或回滚,数据记录正常。

<?php

function getPdoInfo($mysqli)
{
    $result = $mysqli->query("SELECT VERSION()");
    $row1 = $result->fetch();
    $version = $row1[0];

    $result = $mysqli->query("SELECT @@GLOBAL.TX_ISOLATION;");
    // $result = $mysqli->query("SELECT @@GLOBAL.TRANSACTION_ISOLATION;");
    $row2 = $result->fetch();
    $isolation = $row2[0];
    return compact('version', 'isolation');
}

function getConn($ip, $port, $dbbane, $user, $password)
{
    $dsn = "mysql:host=$ip;port=$port;dbname=$dbbane;charset=utf8";
    $mysqli = new PDO($dsn, $user, $password);
    return $mysqli;
}


try {
    $mysqli1 = getConn('127.0.0.1', '3306', 'test', 'root', '');
    $mysqli1 = getConn('192.168.12.12', '3306', 'test2', 'root', '');

    // var_dump(getPdoInfo($mysqli1));
    // var_dump(getPdoInfo($mysqli2));

    $mysqli1->beginTransaction();
    $mysqli2->beginTransaction();

    $num1 = 0;
    $num2 = 0;
    try {
        $name = 'test' . rand(1, 999);
        $age = rand(1, 99);
        $dt = date('Y-m-d H:i:s');
        $sql = "INSERT into test.test_table (`name`,`age`,`create_time`) values ('$name',$age,'$dt');";
        $res = $mysqli1->query($sql);
        $num1 = $res->rowCount();
        // $num1 = 0;

        $sql = "INSERT into test2.test_table (`name`,`age`,`create_time`)) values ('$name',$age,'$dt');";
        $res = $mysqli2->query($sql);
        $num2 = $res->rowCount();
        // $num2 = 0;

        if ($num1 > 0 && $num2 > 0) {
            $mysqli1->commit();
            $mysqli2->commit();

            echo 'COMMIT';
        } else {
            $mysqli1->rollBack();
            $mysqli2->rollBack();

            echo 'ROLLBACK';
        }
    } catch (Exception $e) {
        $mysqli1->rollBack();
        $mysqli2->rollBack();

        var_dump($e->getMessage());
    }
} catch (Exception $e) {
    var_dump($e->getMessage());
}
unset($mysqli1);
unset($mysqli2);

只是不知道在高并发场景下,上面两种跨服务器的事务能否保持数据一致?

posted @ 2024-07-18 17:13  carol2014  阅读(2)  评论(0编辑  收藏  举报