2016-05-31 15 views
17

PHP Documentationは言う:原子性、一貫性、独立性および耐久性(ACID):理解PDOのMySQLの取引

あなたが前のトランザクションが発生したことがない場合、彼らは4つの主要な 機能を提供します。それはコミット があるとき 素人の面では、すべての作業が、それは段階的に行わ であっても、トランザクション内で行われ、と、他の接続からの干渉を受けることなく、安全にデータベース に適用されることが保証されています。

質問:これは、私は彼らがお互いに干渉することなく同時にトランザクションを実行している2つの別々のPHPスクリプトを持つことができること

を意味するのでしょうか?


私は何を意味ON起草 "妨害"

想像我々持って次employees表:

__________________________ 
| id | name | salary | 
|------+--------+----------| 
| 1 | ana | 10000 | 
|------+--------+----------| 

私は似て2つのスクリプトを使用している場合/同じコードであり、正確に同じ時刻に実行されます。

script1.phpscript2.php(両方が同じコードを有する)次のよう

$conn->beginTransaction(); 

$stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?"); 
$stmt->execute(['ana']); 
$row = $stmt->fetch(PDO::FETCH_ASSOC); 

$salary = $row['salary']; 
$salary = $salary + 1000;//increasing salary 

$stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?"); 
$stmt->execute(['ana']); 

$conn->commit(); 

及びイベントのシーケンスを仮定である:

  • script1.phpデータを選択する

  • script2.phpデータ

  • script1.php更新データ

  • script2.php更新データ

  • script1.php(コミット)

  • script2.php起こる選択コミット()が発生する

この結果、アナの給与はどのようになるでしょうか?

  • 11000ですか?これは、コミットが発生する前に情報が取得されたため、1つのトランザクションが他のトランザクションと重複することを意味しますか?

  • 12000ですか?そして、これは、データが更新されて選択された順番にかかわらず、commit()機能がこれらを個別に実行するように強制したことを意味しますか?

あなたが取引して別々のスクリプトが互いに干渉することができます(または干渉しないように)どのように好きなだけを詳しく説明すること自由に感じなさい。

+0

を私はかなり確信していますこれらのスクリプトの1つに対して、 'SQLSTATE [23000]:Integrity constraint violation'エラーがポップアップします。問題は、両方がまったく同じ時刻に実行されているかどうかです。 – icecub

答えて

13

これはphpやpdoとは関係ないので、phpのマニュアルで答えを見つけるつもりはありません。

mysqlのInnodbテーブルエンジンは、SQL標準に準拠して、いわゆるisolation levelsを提供します。ブロッキング/ノンブロッキングの読み出しに伴う分離レベルは、上記の例の結果を決定します。さまざまな分離レベルの意味を理解し、必要に応じて適切なレベルを選択する必要があります。

まとめ:自動コミットをオフにしてシリアル化可能な分離レベルを使用すると、結果は12000になります。他のすべての分離レベルでは、自動コミットを有効にしてシリアル化すると結果は11000になります。結果はすべての独立性レベルの下で12000になる可能性があります。

7

特定の条件(単独のDML文)で判断すると、ここではトランザクションは必要なく、テーブルロックが必要です。それは非常に一般的な混乱です。

すべてのDML文が正しく実行されたか、まったく実行されなかったことを確認する必要がある場合は、トランザクションが必要です。あなたがSELECTの任意の数のトランザクションを必要としない

手段

  • 唯一のDML文がが

を行っている場合は、トランザクションを必要としない

  • を照会し、あなたがシャドウからの優秀な答えで指摘されているように、は適切な分離レベルでここでトランザクションを使用すると、むしろ混乱するでしょう。ここに必要なものはtable lockingです。 InnoDBエンジンでは、テーブル全体をロックする代わりにlock particular rowsを使用することができます。

    給与を1200にする場合は、テーブルロックを使用します。

    か - 簡単な方法 - ちょうどアトミック更新クエリを実行します。すべての給与が記録されます。この場合

    UPDATE employees SET salary = salary + 1000 WHERE name = ? 
    

    を。

    目標が異なる場合は、明示的に明示してください。

    もう一度:一般的な取引は別々のスクリプトの実行とは関係がありません。競合状態のトピックについては、トランザクションではなくテーブル/行ロックに興味があります。これは非常に一般的な混乱で、あなたはより良いまっすぐそれを学ぶ:

    • トランザクションはが正常に実行された1スクリプト内セットのDMLクエリことを確実にするためです。
    • テーブル/行のロックは、他のスクリプトの実行が干渉しないようにすることです。

    トランザクションとロックが干渉する唯一のトピックはdeadlockですが、トランザクションがロックを使用している場合のみです。

  • +0

    質問は、特定の方法で特定のアクションを実行するのではなく、ACIDからIという文字を理解することを目的としていたと思います。少なくともこれが私の解釈方法です。私はあなたがテーブルロックについて書いたものに同意しません。 innodbでは、select文で行レベルのロックを行うことができるので、最後に12000を得るためにテーブル全体をロックする必要はありません。上記のコードでは、selectを行う必要はないことに同意します。これは、操作全体を1回の更新で実行できるためです。しかし、これがトランザクションの分離を理解することを目的とした例に過ぎない場合は、目的を果たします。 – Shadow

    +0

    私は一般的な用語として "テーブルロック"を使用していますが、innodbを使用すると、行レベルのロックが優先されるべきです。ですから、私はあなたのコメントをむしろ専門用語として扱います。質問の意味に関しては、私はおそらく15年前から回答している質問を理解するという点で、おそらく最高の男です。彼らは彼らの特定の問題を研究し始めたOPのためのXY問題としてのACID質問。いずれにしても、両方の答えがお互いを裏付けていると思うので、読者にとってはより良いものにしてください。 –

    4

    悲しいかな、「干渉しない」というのは、プログラマーの助けが必要です。 'トランザクション'の範囲を定義するには、BEGINCOMMITが必要です。そして...

    あなたの例は不十分です。最初の文はSELECT ... FOR UPDATEが必要です。これは、SELECTがフェッチする行に来る可能性が高いとトランザクション処理に伝えます。UPDATEその警告は「干渉を防ぐ」ために重要です。今タイムライン読み取り:

    • script1.phpは
    • script2.phpが
    • script1.phpは(FOR UPDATE
    • script2.phpは、データがブロックされている選択し、それが
    • を待つデータを選択を開始し始めますscript1.phpはデータを更新します
    • script1.php commit()が発生します
    • script2.phpはデータを選択します(新しくコミットされた値を取得します)
    • script2.php更新データ
    • )が(コミット

    起こるscript2.php(注:これは、 'デッドロック'、ただ '待つ' ではありません)