トランザクション分離レベルは、トランザクションが実行されたときに他のトランザクションのデータ変更を定義します。異なる分離レベルはさまざまな程度のデータ分離を提供し、一般的な分離レベルには次のものが含まれます。
コミットされていないことを読んでください
別のトランザクションによってコミットされていないデータを読み取るために1つのトランザクションを許可すると、汚れた読み物が生じる可能性があります。
コミットされた読み物を読んでください
汚れた測定値を避けて、コミットされたデータを読み取ることができるトランザクションは1つだけですが、繰り返しのない測定値が発生する可能性があります。
再現可能な読み取り
トランザクション内のすべてのクエリが同じデータを返すことを確認し、繰り返しのない読みを避けてください。
シリアル化可能
連続的に実行される強制トランザクション、汚い読み取り、繰り返しのない読み、幻の読み取りを完全に避けますが、パフォーマンスは大きな影響を受けます。
PDOは、トランザクションが開始される前にトランザクション分離レベルを設定できます。この操作は通常、SQLステートメントによって行われます。特定の方法は、 PDO :: beginTransaction()を呼び出す前に、設定されたトランザクション分離レベルステートメントを使用して必要な分離レベルを設定することです。例えば:
<span><span><span class="hljs-comment">// 作成する PDO 例</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title function_ invoke__">PDO</span></span><span>(</span><span><span class="hljs-string">'mysql:host=localhost;dbname=test'</span></span><span>, </span><span><span class="hljs-string">'username'</span></span><span>, </span><span><span class="hljs-string">'password'</span></span><span>);
</span><span><span class="hljs-comment">// トランザクション分離レベルをに設定します“繰り返し可能”</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">exec</span></span><span>(</span><span><span class="hljs-string">"SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"</span></span><span>);
</span><span><span class="hljs-comment">// トランザクションを開始します</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">beginTransaction</span></span><span>();
</span><span><span class="hljs-comment">// データベース操作を実行します</span></span><span>
</span><span><span class="hljs-comment">// ...</span></span><span>
</span><span><span class="hljs-comment">// トランザクションを送信します</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">commit</span></span><span>();
</span></span>上記のコードでは、トランザクション分離レベルの設定再現可能な読み取りは、トランザクション分離レベルを再現可能な読み取りに設定します。つまり、現在のトランザクションで実行されたクエリは、他のトランザクションが間にデータを変更したとしても、常に同じ結果を返します。
トランザクションの分離レベルが異なると、並行性の問題に異なる影響があります。並行性の問題を防ぐためのそれらの特定の症状は次のとおりです。
コミットされていないことを読んでください
この分離レベルでは、トランザクションは他のトランザクションがコミットしていないデータを読み取ることができます。他のトランザクションの操作に制限がないため、並行性の問題は非常に発生する傾向があります。
コミットされた読み物を読んでください
トランザクションはコミットされたデータのみを読み取ることができるため、この分離レベルは汚い読み取りの問題を回避します。ただし、依然として繰り返し不可能な読み取りを行うことは可能かもしれません。つまり、トランザクションが同じデータを2回読み取ると、データが変更される可能性があります。データの一貫性が高くないいくつかのシナリオでは、この分離レベルはパフォーマンスと一貫性のバランスをとることができます。
再現可能な読み取り
繰り返し可能な読み取り分離レベルは、トランザクション内のすべてのクエリが一貫したデータを返すことを保証し、非回復可能な読み取りを回避します。ただし、Phantomの読み取りが発生する場合があります。つまり、別のトランザクションにより、現在のトランザクションクエリ間に新しいデータが挿入されます。この分離レベルは、同時の書き込み操作をより厳しく制御するため、データの一貫性の向上に役立ちます。
シリアル化可能
シリアル化分離レベルは最も厳格であり、トランザクションのシリアル化を強制することによるダーティリーディング、非繰り返しの読書、ファンタジーリーディングなど、すべての並行性の問題を回避します。この分離レベルはパフォーマンスに大きな影響を与え、通常、厳密な一貫性が必要なシナリオに適しています。
適切なトランザクション分離レベルを選択するには、特定のビジネスニーズに基づいてトレードオフが必要です。
高性能を必要とするが、高いデータの一貫性を必要としないアプリケーションシナリオである場合、提出された分離レベルを読むことを選択できます。これにより、Dirty Readsがデータを変更するための同時トランザクションを許可します。
繰り返し可能な読み取りは、ほとんどのアプリケーションでは、繰り返し不可能で汚れた読み取りを防ぐことができ、データの一貫性を確保しながら、パフォーマンスの損失は比較的少ないためです。
データの厳密な一貫性と低い並行性を確保する必要があるシステムでは、シリアル化された分離レベルを選択できます。そのパフォーマンスは貧弱ですが、すべての並行性の問題を完全に回避できます。
ユーザーのアカウント残高が同時操作のためにエラーを引き起こさないことを確認する必要がある銀行システムを開発しているとします。繰り返し可能な読み取り分離レベルを設定することにより、1つのトランザクションでクエリされたバランスが他のトランザクションによって変更されるのを防ぐことができます。
<span><span><span class="hljs-comment">// 作成する PDO 例</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title function_ invoke__">PDO</span></span><span>(</span><span><span class="hljs-string">'mysql:host=localhost;dbname=bank'</span></span><span>, </span><span><span class="hljs-string">'root'</span></span><span>, </span><span><span class="hljs-string">'password'</span></span><span>);
</span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">exec</span></span><span>(</span><span><span class="hljs-string">"SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"</span></span><span>);
</span><span><span class="hljs-comment">// トランザクションを開始します</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">beginTransaction</span></span><span>();
</span><span><span class="hljs-comment">// アカウントの残高を確認してください</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"SELECT balance FROM accounts WHERE account_id = ?"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([</span><span><span class="hljs-number">1</span></span><span>]);
</span><span><span class="hljs-variable">$balance</span></span><span> = </span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">fetchColumn</span></span><span>();
</span><span><span class="hljs-comment">// 特定のビジネスロジックを実行します</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$balance</span></span><span> > </span><span><span class="hljs-number">100</span></span><span>) {
</span><span><span class="hljs-comment">// 控除操作</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"UPDATE accounts SET balance = balance - 100 WHERE account_id = ?"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([</span><span><span class="hljs-number">1</span></span><span>]);
}
</span><span><span class="hljs-comment">// トランザクションを送信します</span></span><span>
</span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">commit</span></span><span>();
</span></span>この例では、反復可能な読み取り分離レベルが設定されており、他のトランザクションの変更によりクエリバランスが変更されないようにし、データの矛盾を回避します。
PDO :: beginTransaction()は、 PHPでデータベーストランザクションを管理するのに役立つ強力なツールです。合理的なトランザクション分離レベルの設定と組み合わせることにより、並行性の問題を効果的に防止し、データの一貫性と整合性を確保することができます。開発プロセス中に、パフォーマンスとデータの一貫性の関係のバランスをとるために、ビジネスのニーズに基づいて適切なトランザクション分離レベルを選択する必要があります。
関連タグ:
PDO