web-dev-qa-db-ja.com

トランザクション内のMySQLトランザクション

Mysqlデータベースを使用するPHPスクリプトで、最近、たまたま別のトランザクション内にあるポイントでトランザクションを使用する必要がありました。すべての私のテストは、これがうまく機能していることを示しているようです、しかし、私はこの使用法に関するドキュメントを見つけることができません。

確認したい-トランザクション内のトランザクションはmysqlで有効ですか?もしそうなら、ネストされたトランザクションの深さをいくつ調べることができるでしょうか? (つまり、通常に戻るのにかかるロールバックの数)

前もって感謝します、ブライアン

49
Brian

マニュアルのこのページに興味があるかもしれません: 12.3.3。暗黙のコミットを引き起こすステートメント ;いくつかの文を引用すると:

このセクションにリストされているステートメント(およびそれらの同義語)は、ステートメントを実行する前にCOMMITを実行したかのように、トランザクションを暗黙的に終了します。

そして、ページのもう少し:

トランザクション制御とロックのステートメント。 BEGINLOCK TABLESSET autocommit = 1(値がまだ1でない場合)、START TRANSACTIONUNLOCK TABLES

この段落も参照してください。

トランザクションはネストできません。
これは、START TRANSACTIONステートメントまたはその類義語の1つを発行したときに、現在のトランザクションに対して暗黙的にcommitが実行された結果です。

50
Pascal MARTIN

他の皆の答えとは逆に、トランザクション内でトランザクションを効果的に作成でき、それは本当に簡単です。 SAVEPOINTの場所を作成し、ROLLBACK TOsavepointを使用してトランザクションの一部をロールバックします。ここで、savepointは、セーブポイントに付ける名前です。 MySQLのドキュメントへのリンク: http://dev.mysql.com/doc/refman/5.0/en/savepoint.html そしてもちろん、トランザクション内のどのクエリも次のタイプであってはなりません暗黙的にコミットするか、トランザクション全体がコミットされます。

例:

START TRANSACTION;

# queries that don't implicitly commit

SAVEPOINT savepoint1;

# queries that don't implicitly commit

# now you can either ROLLBACK TO savepoint1, or just ROLLBACK to reverse the entire transaction.

SAVEPOINT savepoint2;

# queries that don't implicitly commit

# now you can ROLLBACK TO savepoint1 OR savepoint2, or ROLLBACK all the way.
# e.g.

ROLLBACK TO savepoint1;
COMMIT; # results in committing only the part of the transaction up to savepoint1

PHP私はこのようなコードを書いており、それは完全に機能します:

foreach($some_data as $key => $sub_array) {
  $result = mysql_query('START TRANSACTION'); // note mysql_query is deprecated in favor of PDO
  $rollback_all = false; // set to true to undo whole transaction
  for($i=0;$i<sizeof($sub_array);$i++) {
    if($sub_array['set_save'] === true) {
      $savepoint = 'savepoint' . $i;
      $result = mysql_query("SAVEPOINT $savepoint");
    }
    $sql = 'UPDATE `my_table` SET `x` = `y` WHERE `z` < `n`'; // some query/queries
    $result = mysql_query($sql); // run the update query/queries

    $more_sql = 'SELECT `x` FROM `my_table`'; // get data for checking
    $result = mysql_query($more_sql);

    $rollback_to_save = false; // set to true to undo to last savepoint
    while($row = mysql_fetch_array($result)) {
      // run some checks on the data
      // if some check says to go back to savepoint:
      $rollback_to_save = true; // or just do the rollback here.
      // if some check says to rollback entire transaction:
      $rollback_all = true;
    }
    if($rollback_all === true) {
      mysql_query('ROLLBACK'); // rollback entire transaction
      break; // break out of for loop, into next foreach
    }
    if($rollback_to_save = true) {
      mysql_query("ROLLBACK TO $savepoint"); // undo just this part of for loop
    }
  } // end of for loop
  mysql_query('COMMIT'); // if you don't do this, the whole transaction will rollback
}
57
Buttle Butkus

確認したい-トランザクション内のトランザクションはmysqlで有効ですか?

番号。

13

MySqlはネストされたトランザクションをサポートしていません。ただし、エミュレートできる方法はいくつかあります。まず、トランザクションの形式としてセーブポイントを使用できるため、2つのレベルのトランザクションが可能になります。私はこれをテストに使用しましたが、プロダクションコードで使用した場合の制限についてはわかりません。より簡単な解決策は、2番目のbegin transactionを無視して、代わりにカウンターを増やすことです。 commitごとに、値を減らします。ゼロに達したら、実際にcommitを実行します。これには明らかな制限があります。例えば。ロールバックはallトランザクションをロールバックしますが、トランザクションをエラー処理にのみ使用する場合は、それで問題ない場合があります。

8
troelskn

このスレッドにはいくつかの素晴らしい答えがありますが、MySQLストレージエンジンとしてinnoDBを使用していて、MySQL 5.0.3以降を使用している場合は、追加の作業を行わなくても、箱から出してすぐにネストされたトランザクションを取得できます。このスレッドで他の人が説明しているファンシーなテクニック。

XAトランザクションのMySQLドキュメントから:

MySQL 5.0.3以降では、XAトランザクションのサーバー側サポートが提供されます。現在、このサポートはInnoDBストレージエンジンで利用できます。 MySQL XA実装は、X/Open CAEドキュメントの分散トランザクション処理:XA仕様に基づいています。このドキュメントはThe Open Groupによって公開されており、 http://www.opengroup.org/public/pubs/catalog/c193.htm で入手できます。現在のXA実装の制限については、セクションX.5「XAトランザクションの制限」で説明されています。

あなただけの私のXAトランザクションの例:

# Start a new XA transaction
XA START;

    # update my bank account balance, they will never know!
    UPDATE `bank_accounts` SET `balance` = 100000 WHERE `id` = 'mine';

    # $100,000.00 is a bit low, I'm going to consider adding more, but I'm not sure so 
    # I will start a NESTED transaction and debate it...
    XA START;

        # max int money! woo hoo!
        UPDATE `bank_accounts` SET `balance` = 2147483647 WHERE `id` = 'mine';

    # maybe thats too conspicuous, better roll back
    XA ROLLBACK;


# The $100,000 UPDATE still applies here, but the max int money does not, going for it!
XA COMMIT;

# Oh No!  Sirens!  It's the popo's!!! run!!
# What the hell are they using ints for money columns anyway!  Ahhhh!

XAトランザクションのMySQLドキュメント:

I <3 XAトランザクション4 Eva!

6
pfuri

テストの方法論を確認することをお勧めします。 MaxDB の外では、MySQLはリモートでネストされたトランザクションのようなものをサポートしていません。

1
Alan Storm
1
K. Norbert