4

PHP で書かれた Web アプリケーションの更新システムを開発しています。更新の過程で、一連の MySQL スクリプトを実行する必要があるかもしれません。

スクリプトを実行する基本的なプロセスは次のとおりです。

  1. Mysql スクリプトを検索する
  2. 取引を開始する
  3. スクリプトには複数のクエリを含めることができるため、mysqli_multi_query を使用して各スクリプトを実行します。
  4. すべてがうまくいけばトランザクションを COMMIT し、そうでなければ ROLLBACK します。

私のコードは次のようになります。

$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 はエラーを生成します (説明のために、列が一意であり、 = 1keyの行が既に存在するとします)。key

この場合、実行されたすべてのクエリをロールバックしたいと考えています。しかし、1.5.1.0 の最初の挿入は (正しく) データベースにありませんが、1.5.0.0 からの更新は正常に実行されました。

備考:

  1. 私の最初のオプションは、すべてのスクリプトからすべてのクエリを「;」で分割することでした。クエリを個別に実行します。データベースに HTML コードを挿入できる必要があるため、これはオプションではありません (例: "& nbsp;" のようなものを挿入したい場合)。
  2. 私はすでに StackOverflow と google を検索し、このようなソリューション出くわしましたが、関数を使用してすべてのクエリを分割するよりも、mysqli_multi_query のようなソリューションを使用することをお勧めします。デバッグ目的でより理解しやすく、簡単です
  3. テストはしていませんが、すべてのスクリプトをマージして、クエリだけを実行できると思います。ただし、一度に 1 つのスクリプトを実行すると、どのスクリプトにエラーがあるかを特定できると便利です。
  4. テーブル エンジンは InnoDB です。

これを機能させる方法を指摘できれば幸いです。

4

2 に答える 2

2

編集:最初のクエリが失敗したmysqli_multi_query()場合にのみ false を返します。最初のクエリが失敗しない場合、コードが実行され、成功した場合は空のままになります。成功または失敗する可能性のあるすべてのmysqli 関数の後に、エラーをチェックする必要があります。mysql_store_result()mysqli_error()

于 2011-08-26T04:07:36.017 に答える
0

OK、デバッグにもう 1 日費やした後、問題を発見しました。

実際には、コード自体や mysqli 関数とは何の関係もありません。私は、DDL ステートメントをサポートする MS SQL トランザクションに慣れています。MySQL は DDL ステートメントをサポートせず、データを暗黙的にコミットします ( Implicit commit )。データを自動コミットするスクリプトの 1 つに DROP テーブルが 1 つあります。

于 2014-05-05T11:08:33.770 に答える