PDO を介して接続します。クエリを開始する前に、まず PDO がトランザクションを管理する方法を理解する必要があります。トランザクションは、原子性、一貫性、分離性、耐久性という 4 つの主要な特性 (ACID) をサポートします。平たく言えば、トランザクション内で実行される操作は、段階的に実行される場合でも、他の接続からの干渉なしに安全にデータベースに適用され、コミットされることが保証されます。トランザクション操作はリクエストに応じて自動的に元に戻すこともできるため (まだコミットされていないことが前提)、スクリプトでのエラーの処理が容易になります。
トランザクションは通常、変更のバッチを「蓄積」し、同時にそれらを有効にすることによって実装されます。これを行う利点は、これらの変更の効率を大幅に向上できることです。言い換えれば、トランザクションによってスクリプトが高速化され、潜在的により堅牢になる可能性があります (ただし、そのような利点を得るにはトランザクションを正しく使用する必要があります)。
残念ながら、すべてのデータベースがトランザクションをサポートしているわけではないため、最初に接続が開かれたときに PDO をいわゆる「自動コミット」モードで実行する必要があります。オートコミット モードは、データベースがトランザクションをサポートしている場合は各クエリ実行に独自の暗黙的なトランザクションがあり、データベースがトランザクションをサポートしていない場合はトランザクションが存在しないことを意味します。トランザクションが必要な場合は、PDO::beginTransaction() メソッドを使用して開始する必要があります。基礎となるドライバーがトランザクションをサポートしていない場合、PDOException がスローされます (これは、エラー処理設定に関係なく、重大なエラー状態です)。トランザクションが開始されると、トランザクション内のコードが正常に実行されたかどうかに応じて、PDO::commit() または PDO::rollBack() を使用してトランザクションを完了できます。
PDO は、ドライバー層でトランザクション処理機能があるかどうかのみをチェックします。実行時条件によってトランザクションが利用できないことを意味し、データベース サービスがトランザクション開始リクエストを受け入れた場合でも、PDO::beginTransaction() はエラーなしで TRUE を返します。
MySQL データベースの MyISAM データ テーブルでトランザクションを使用しようとすることが良い例です。
スクリプトが終了するとき、または接続が閉じられようとするときに、未完了のトランザクションがある場合、PDO は自動的にトランザクションをロールバックします。この安全対策は、スクリプトが予期せず終了した場合の不整合を回避するのに役立ちます。トランザクションが明示的にコミットされていない場合は、何か問題が発生したと想定されるため、データを安全に保つためにロールバックが実行されます。
自動ロールバックは、PDO::beginTransaction() を通じてトランザクションを開始した後にのみ発生します。トランザクションを開始するクエリを手動で発行した場合、PDO はそれを知る方法がないため、必要に応じてロールバックできません。
例 #1 トランザクションでのバッチ処理の実行
次の例では、新しい従業員用に一連のエントリが作成され、ID 23 が割り当てられると想定します。個人の基本データを登録することに加えて、給与も記録する必要があります。 2 つの更新を個別に完了するのは簡単ですが、それらを PDO::beginTransaction() 呼び出しと PDO::commit() 呼び出しで囲むことで、完了するまで他のユーザーが変更を確認できないようにすることができます。エラーが発生した場合、catch ブロックはトランザクションの開始以降に発生したすべての変更をロールバックし、エラー メッセージを出力します。
<?php try { $dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2', array(PDO::ATTR_PERSISTENT => true)); echo "Connected\n"; } catch (Exception $e) { die("Unable to connect: " . $e->getMessage()); } try { $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->beginTransaction(); $dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')"); $dbh->exec("insert into salarychange (id, amount, changedate) values (23, 50000, NOW())"); $dbh->commit(); } catch (Exception $e) { $dbh->rollBack(); echo "Failed: " . $e->getMessage(); } ?>
はトランザクション内での変更に限定されず、複雑なクエリを発行してデータを抽出することもでき、トランザクションがアクティブなときにその情報を使用してさらに変更やクエリを構築することもでき、他のユーザーがそれを実行できないようにすることができます。操作の進行中に変更を加えます。