mysqli事务在insert失败时无法回滚

Posted

技术标签:

【中文标题】mysqli事务在insert失败时无法回滚【英文标题】:Mysqli transaction fail to rollback when insert is failed 【发布时间】:2021-10-03 19:58:18 【问题描述】:

我有 3 个数据库,我需要创建数据库 A,然后创建数据库 B,然后创建链接数据库 A_B。

我在php中使用mysqli事务,有一个奇怪的情况(这是我第一次使用php事务),失败时它永远不会回滚,比如数据库A插入失败,但B仍然创建。和 A_B 创建不正确。

mysqli_begin_transaction($link);
try

            $sql = "INSERT INTO A (
                     ....)
                    VALUES
                    (?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?,?);";
            $stmt = mysqli_prepare($link,$sql);
            mysqli_stmt_bind_param($stmt,"sssssssssssss",
                   ....
            );
            mysqli_stmt_execute($stmt);
            $param_new_A_Rec = mysqli_insert_id($link);
            
            for($i = 0; $i < $tot; $i++)
     
                            
               $sql = "INSERT INTO B (..)
                VALUES
                    (?, ?, ?, ?, ?, ?, ?, ?, ?,?,?,?);";

            $stmt = mysqli_prepare($link,$sql);
            mysqli_stmt_bind_param($stmt,"ssssssssssss",
                   ...
            );

            mysqli_stmt_execute($stmt);
            $param_new_B_Rec = mysqli_insert_id($link);
            
            $sql = "INSERT INTO A_B (
                    param_new_A_Rec,
                    param_new_B_Rec,
                     ....                       
              (?,?,?,?,?,?);";
            $stmt = mysqli_prepare($link,$sql);
            mysqli_stmt_bind_param($stmt,"ssssss",
                    ....
            );
            mysqli_stmt_execute($stmt);

            


            mysqli_commit($link);
            
    catch (mysqli_sql_exception $exception) 

            mysqli_rollback($link);
          
            throw $exception;
            
    

为什么如果 A 失败了,它永远不会命中 rollback() 并且它创建了不正确的 A_B 和 B 数据?我在这里错过了什么吗? 任何帮助将不胜感激!

【问题讨论】:

嘿,事务来自数据库而不是 PHP,看来你没有遗漏什么,你可以检查一下: 1. 一些MySQL DB Engines 不支持事务,在链接中是doc,您可以在其中检查您正在使用的那个是否支持它。 2.任何与mysqli_sql_exception无关的错误都不会触发rollback 你好 Juan,引擎是 InnoDB。我有一个案例,当我将日期插入数据库 A 时,该字段是 tinyInt(),我按下“false”,它无法创建数据库 A,但它继续使用数据库 B 和数据库 A_B,外键链接不正确,这应该触发 mysqli_sql_exception 吗? 该引擎有支持,您尝试在catch 块中打印一些内容吗?看看它是否被捕获。 我错过了编辑。只是为了尝试,您可以将回滚放在不会产生影响的提交之前; false 作为数据类型可以被认为是0,如果您在 AI 列中有以前的寄存器,mysqli_insert_id 将返回一个有效的 id。 请告诉我们:是否会引发异常?您是否启用了例外?此代码是否在命名空间内?如果创建了 B 和 A_B,你怎么知道 A 失败?听起来好像 A 成功完成了,否则你会得到异常。 【参考方案1】:

其实我需要加上这个

"mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);"

现在它正在捕获无效用例:

PHP 致命错误:未捕获的 mysqli_sql_exception:不正确的整数值:'' for column 'boolean_X' at row 1 in yourFile.php

【讨论】:

以上是关于mysqli事务在insert失败时无法回滚的主要内容,如果未能解决你的问题,请参考以下文章

PHP MYSQLI中事务处理

事务无法在 codeigniter 中回滚

外部事务失败时回滚内部事务

mysqli_commit 失败会自动回滚吗?

只有第一个 Mysqli Insert 查询与 PHP 工作,而其他人失败

在不自动提交的情况下,回滚段有啥用。