使用mysqli_multi_query和事务运行多个查询

时间:2011-08-25 17:45:54

标签: php transactions mysqli mysqli-multi-query

我正在为用PHP编写的Web应用程序开发更新系统。在更新过程中,我可能需要执行一堆MySQL脚本。

运行脚本的基本过程是:

  1. 搜索Mysql脚本
  2. 开始交易
  3. 使用mysqli_multi_query执行每个脚本,因为脚本可以包含多个查询
  4. 如果一切顺利,请执行该事务,否则返回ROLLBACK。
  5. 我的代码类似于:

    $link = mysqli_connect(...);
    
    mysqli_autocommit($link, false);
    
    // open dir and search for scripts in file.
    // $file is an array with all the scripts
    foreach ($scripts as $file) {
    
        $script = trim(file_get_contents($scriptname));
    
        if (mysqli_multi_query($link, $script)) {
            while (mysqli_next_result($link)) {
                if ($resSet = mysqli_store_result($link)) { mysqli_free_result($resSet); }
    
                if (mysqli_more_results($link)) { }
            }
        }
    
        // check for errors in any query of any script
        if (mysqli_error($link)) {
            mysqli_rollback($link);
            return;
        }
    }
    mysqli_commit($link);
    

    以下是脚本示例(用于演示目的):

    script.1.5.0.0.sql:
    update `demo` set `alias` = 'test1' where `id` = 1;
    update `users` set `alias` = 'user1' where `id` = 1;
    
    script 1.5.1.0.sql: 
    insert into `users`(id, key, username) values(3, '100', 'column key does not exist');
    insert into `users`(id, key, username) values(3, '1', 'column key exists');
    

    在这种情况下,脚本1.5.0.0将无错执行,脚本1.5.1.0将生成错误(出于演示目的,假设列key是唯一的,并且已经有一行{{1 }} = 1)。

    在这种情况下,我想回滚每个执行的查询。但是,1.5.1.0的第一个插入不在数据库中(正确),但1.5.0.0的更新已成功执行。

    说明:

    1. 我的第一个选择是用“;”拆分每个脚本的每个查询并独立执行查询。这不是一个选项,因为我必须能够将HTML代码插入数据库(例如:如果我想插入类似“& nbsp;”的话)
    2. 我已经搜索过StackOverflow和google并遇到了像this one这样的解决方案,但我更喜欢使用像mysqli_multi_query这样的解决方案而不是使用函数来拆分每个查询。调试目的更容易理解和简单
    3. 我没有测试过它,但我相信我可以合并所有脚本并执行一个查询。但是,一次执行一个脚本是有用的,这样我就可以确定哪个脚本有错误。
    4. 表引擎是InnoDB。
    5. 感谢您是否可以指出某种方式使其发挥作用。

2 个答案:

答案 0 :(得分:2)

编辑: mysqli_multi_query()仅在第一次查询失败时才返回false。如果第一个查询没有失败,那么您的代码将运行mysql_store_result(),如果成功则会使mysqli_error()为空。您需要在每个可以成功或失败的 mysqli函数之后检查错误。

答案 1 :(得分:0)

好的,经过另一天的调试后,我发现了这个问题。

实际上,它与代码本身或mysqli函数无关。我习惯于支持DDL语句的MS SQL事务。 MySQL不支持DDL语句并隐式提交数据(Implicit commit)。我在其中一个自动提交数据的脚本中有一个DROP表。