PHPのPDOで同時に複数の操作を行い整合性を保つ「トランザクション」 @MySQL


スポンサーリンク

はじめに

PHPのPDOを触っていると、2つのテーブルを同時に更新したいシチュエーションが発生します。

例として、商品購入情報を持ったテーブルと、支払い情報を持ったテーブルを更新する場合を挙げます。
前者のテーブルには、Aさんが購入した商品の一覧が挿入され、
後者のテーブルには、Aさんがクレジットカードで支払った金額などが挿入されるとします。
この場合、商品購入情報と支払い情報の整合性がとれなければなりません。
支払いが完了していないのに購入したことになっていたり、支払ったにも関わらず購入していないことになってはなりません。

ここで、「トランザクション」という仕組みを使用することで、すべての処理がうまくいった場合のみ更新を反映させ(Commit)、どれか1つでも失敗した場合はすべて取り消す(RollBack)ことができます。直前にINSERTしたレコードのIDを取得するlastInsertId()も途中で使用することができるので、非常に便利です。また、実際にDBに書き込む回数が減るため、速度向上にもつながります。

スポンサーリンク

使用してみる

基本的なPDOの使用方法はhttps://tanidaiz.com/phpからmysqlを利用する方法/に載せていますが、このページのdsn.phpに、

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

を追記します。これにより、エラー時に例外を投げるようになります。

次にやることは、トランザクションを使用するためのひな形を適用することです。

$pdo->beginTransaction();でトランザクションを開始し、
$pdo->commit();で変更が反映され、
$pdo->rollBack();で変更が取り消されます。

try{
    $pdo->beginTransaction(); // トランザクションを開始
    
    // 行いたい処理
    
    $pdo->commit(); // 反映される
}catch(Exception $e){
    $pdo->rollBack(); // 取り消される
    
    // エラー時処理
}

行いたい処理、エラー時処理はご自身で変更してください。

トランザクションの機能が正常に動いていることを確認するためには、例えば、正しく動くINSERT文やUPDATE文を1文実行させ、次に、存在しないテーブルにINSERTしようとする文(動かない文)を実行させます。そうすると、前者のINSERT文は反映されず、エラー時処理に移ることがわかります。

$pdo->lastInsertId()は、commit後には必ず0が返ってくるため、$pdo->commit();よりも前に実行するようにしましょう。
以上でトランザクションを使用することができます。
データベースの整合性はACIDという原則に入っており、非常に重要なものです。トランザクションを使用することで、「すべて反映されるか、全く反映されない」という状態を実現でき、データベースの一貫性を保つことにつながります。また、トランザクションの処理中は他の場所から処理中のデータを変更されることがありません。

ご覧いただきありがとうございました。

参考

PHP: トランザクションおよび自動コミット - Manual

last

フォローする