【问题标题】:Record deleted during a transaction交易期间删除的记录
【发布时间】:2014-11-19 23:05:28
【问题描述】:

我有一个每秒处理许多查询的系统。我使用mysqlPHP 对我的系统进行编码。

我的问题是mysqli事务仍然提交事务,即使记录被其他用户同时删除,我所有的表都在使用InnoDB

这就是我使用 mysqli 编码交易的方式:

mysqli_autocommit($dbc,FALSE);
$all_query_ok=true;

$q="INSERT INTO Transaction() VALUES()";
mysqli_query ($dbc,$q)?null:$all_query_ok=false;

$q="INSERT INTO Statement() VALUES()";
mysqli_query ($dbc,$q)?null:$all_query_ok=false;

if($all_query_ok==true){
    //all success
    mysqli_commit($dbc);
}else{
    //one of it failed , rollback everything.
    mysqli_rollback($dbc);
}

以下是另一个用户在其他脚本中同时执行的查询,然后最终弄乱了预期的系统行为,

$q="DELETE FROM Transaction...";
mysqli_query ($dbc,$q)?null:$all_query_ok=false;

请指教,我是否错误地执行了交易?我已阅读有关行级锁定的信息,并相信 innoDB 在事务期间确实锁定了记录

【问题讨论】:

  • 您可以使用mysqli::begin_transaction
  • @TiMESPLiNTER 和 mysqli_autocommit() 有什么区别吗?
  • mysqli_autocommit() 仅定义您执行的查询是否在执行后立即提交。所以你必须关闭它(就像你已经在上面的代码中所做的那样)才能使用事务。
  • 不要在无声中投票,下拉评论让我知道如何改进问题

标签: php mysql sql transactions table-locking


【解决方案1】:

我不知道您说的是哪种交易,但是通过mysqli 扩展,我使用以下方法来处理交易:

那么流程是这样的:

  1. 使用mysqli::begin_transaction 开始新事务
  2. 执行您的 SQL 查询
  3. 成功时使用 mysqli::commit 确认您的查询在第 2 步中所做的更改如果您在第 2 步中执行查询期间出错,请使用 mysqli::rollback 恢复他们所做的更改。李>

您可以将事务视为查询的临时缓存。它在某种程度上类似于带有ob_* 函数的PHP 中的输出缓存。只要您没有刷新缓存数据,屏幕上就不会发生任何事情。事务也是如此:只要您没有提交任何内容(并且自动提交已关闭),数据库中就不会发生任何事情。

【讨论】:

    【解决方案2】:

    我对行级锁定做了一些研究,它可以锁定记录以防止删除或更新

    更新

    Official Documentation

    开始交易之后,我必须选择我想要锁定的记录,如下所示

    SELECT * FROM Transaction WHERE id=1 FOR UPDATE
    

    这样记录就会被锁定到transaction end

    此方法不适用于 MyISAM 类型表

    【讨论】:

      【解决方案3】:

      看起来像race condition 的典型示例。您并行执行两个修改数据的并发脚本。可能您的第一个脚本成功插入记录并提交事务,然后第二个脚本成功删除记录。不过,我不确定您所说的“其他用户在其他脚本中同时执行的查询”是什么意思。

      【讨论】:

        【解决方案4】:

        你必须这样做:

        mysqli_autocommit($dbc,FALSE);
        
        $dbc->begin_transaction();
        
        $all_query_ok=true;
        
        $q="INSERT INTO Transaction() VALUES()";
        mysqli_query ($dbc,$q)?null:$all_query_ok=false;
        
        $q="INSERT INTO Statement() VALUES()";
        mysqli_query ($dbc,$q)?null:$all_query_ok=false;
        
        if($all_query_ok==true){
            //all success
            mysqli_commit($dbc);
        }else{
            //one of it failed , rollback everything.
            mysqli_rollback($dbc);
        }
        

        在调用begin_transaction时可以使用面向对象的或者过程式的风格(我更喜欢面向对象的)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-02-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-29
          • 2013-02-14
          • 2018-06-18
          • 1970-01-01
          相关资源
          最近更新 更多