レシピ
データベース PDO
PDOのトランザクション
データベースの操作において欠かすことのできないトランザクションについて、PDOでの実用的なコード例を交えて紹介します。
この記事のポイント
- データベースのトランザクションについて知る
- PDOでトランザクションを実装する
- データベース別にトランザクションを実装する
目次
PDOでトランザクションを実装する
今回はPDOでトランザクションを実装する方法について解説します。
PDO自体の基本的な内容については「PDOについて」を、データベースへの接続方法については「PDOを使ってデータベースへ接続」をご覧ください。
データベースのトランザクションについて
まずはデータベースの「トランザクション」についてご紹介します。
ここのセクションだけでトランザクションがどういうことを行うか、どうしてわざわざ使う必要があるかをザックリ理解することができます。
データベースにおけるトランザクションは、複数のデータ更新処理(参照を除く新規登録、更新、削除)を「コミット(処理実行)」の命令があるまで仮実行(下書きのようなイメージ)に留めておき、コミットの命令が出された時に一括して決定処理を行います。
トランザクションのイメージ
処理を一度のタイミングで集中して行うため、複数の更新処理を行う場合は基本的に処理速度が向上します。
また、トランザクション処理を行なっている間は、「コミット(処理実行)」か「ロールバック(処理取り消し)」のいずれかが行われるまでは他のトランザクション処理を受け付けません。
そのため、データベースの同時アクセスによるデータの行き違い(データの不整合)も未然に防ぐことができます。
以上の理由から、適切なタイミングでトランザクション処理を行うとシステムの高速化&堅牢性を同時に向上させる効果があります。
PDOのトランザクションの基本的な流れを確認する
PDOではトランザクションを簡単に実装する機能が備わっています。
ここで基本的な流れをここでご紹介し、続いてMySQL、PostgreSQL、SQLiteのそれぞれのデータベースごとに実装する例をご紹介していきます。
PDOのトランザクションコード例
try {
// DBへ接続
$dbh = new PDO("mysql:host=127.0.0.1; dbname=test; charset=utf8", 'username', 'password');
// トランザクション開始
$dbh->beginTransaction();
// ここにデータベース更新系の処理が入る
// コミット
$dbh->commit();
} catch(PDOException $e) {
// ロールバック
$dbh->rollBack();
// エラーメッセージ出力
echo $e->getMessage();
die();
}
// 接続を閉じる
$dbh = null;
beginTransactionメソッドがトランザクションの開始の合図となります。
この合図から、「commitメソッド」か「rollBackメソッド」が実行されるまで処理を仮状態とし、いずれかのメソッドが呼び出された瞬間に全反映 or 全キャンセルが実行されます。
トランザクションの途中でデータベースが何かしらのエラーを起こした場合はPDOExceptionオブジェクトの例外が投げられるので、上記のようにtry文〜catch文で囲む形が基本的な使い方となります。
全て正常であればcommitメソッドで処理を実行し、もし途中でエラーが起こってしまった場合はcatch文でPDOExceptionオブジェクトを受け取ってrollBackメソッドでデータベースを処理実行前の状態に巻き戻します。
以上のように、トランザクションを取り入れることで処理全体が正常に終了した場合のみデータベースを更新し、一部でもうまく行かなかった場合は処理前の状態に戻すことでデータの整合性を保つことができます。
MySQL / MariaDBでトランザクションを実装する
まずはMySQLとMariaDBからトランザクションを実装していきます。
この2つのデータベースは共通の方法を使用することができます。
操作前のテーブルには次のデータが入っています。
操作前のテーブル
ここでは、idが4のデータを更新していきます。
commitメソッドとrollBackメソッドの違いについて、それぞれ実行することで解説していきます。
まずはcommitメソッドを使った通常の更新処理を実行してみます。
コード例
<?php
// 変数の初期化
$sql = null;
$res = null;
$dbh = null;
try {
// DBへ接続
$dbh = new PDO("mysql:host=127.0.0.1; dbname=test; charset=utf8", 'username', 'password');
// トランザクション開始
$dbh->beginTransaction();
// UPDATE
$sql = "UPDATE user_list SET age = 24 WHERE id = 4";
// クエリ実行
$res = $dbh->query($sql);
// コミット
$dbh->commit();
} catch(PDOException $e) {
// ロールバック
$dbh->rollBack();
// エラーメッセージ出力
echo $e->getMessage();
die();
}
// 接続を閉じる
$dbh = null;
正常に処理されると、テスト二郎さんのageが24に更新されます。
操作後のテーブル
上記の処理ではcommitメソッドが実行されるまではデータの更新も保留状態となり、実行されたタイミングで初めてデータベースへ反映されます。
この挙動を確かめるために、次はあえてrollBackメソッドを実行してみます。
先ほど更新したテスト二郎さんのageを、次は25になるようにSQLを変更して処理を実行します。
コード例
<?php
// 変数の初期化
$sql = null;
$res = null;
$dbh = null;
try {
// DBへ接続
$dbh = new PDO("mysql:host=127.0.0.1; dbname=test; charset=utf8", 'username', 'password');
// トランザクション開始
$dbh->beginTransaction();
// UPDATE
$sql = "UPDATE user_list SET age = 25 WHERE id = 4";
// クエリ実行
$res = $dbh->query($sql);
// 強制的にロールバックする
$dbh->rollBack();
} catch(PDOException $e) {
// ロールバック
$dbh->rollBack();
// エラーメッセージ出力
echo $e->getMessage();
die();
}
// 接続を閉じる
$dbh = null;
操作後のテーブル (ロールバック)
上記のコードは処理が正常であっても強制的にロールバックを実行するため、何度実行してもデータを更新できないことが確認できます。
以上、MySQLとMariaDBでのトランザクションでした。
PostgreSQLでトランザクションを実装する
続いて、PostgreSQLでトランザクションを実装します。
基本的なコードは上記MySQLと同様です。
操作前のテーブル
今回はidに5を持つテスト奈津子さんのデータを更新します。
コード例
<?php
// 変数の初期化
$sql = null;
$res = null;
$dbh = null;
try {
// DBへ接続
$dbh = new PDO("pgsql:host=127.0.0.1; dbname=test;", 'username', 'password');
// SQL作成
$sql = "UPDATE user_list SET age = 30 WHERE id = 5";
// SQL実行
$res = $dbh->query($sql);
// コミット
$dbh->commit();
} catch(PDOException $e) {
// ロールバック
$dbh->rollBack();
echo $e->getMessage();
die();
}
// 接続を閉じる
$dbh = null;
操作後のテーブル
処理が正常に実行されると、テスト奈津子さんのageが30に更新されます。
もし途中でエラーが起こった場合はcatch文へと移動し、rollBackメソッドによってデータベースが処理前の状態に復帰されます。
以上、PostgreSQLでのトランザクションでした。
SQLiteでトランザクションを実装する
最後にSQLiteでトランザクションを実装します。
全体の流れは上記2つのデータベースと同じ内容です。
操作前のテーブル
ここでは、idが4のテスト有希さんのデータを更新していきます。
コード例
<?php
// 変数の初期化
$sql = null;
$res = null;
$dbh = null;
try {
// DBへ接続
$dbh = new PDO("sqlite:./sqlite/test.sqlite3");
// SQL作成
$sql = "UPDATE user_list SET age = 28 WHERE id = 4";
// SQL実行
$res = $dbh->query($sql);
// コミット
$dbh->commit();
} catch(PDOException $e) {
// ロールバック
$dbh->rollBack();
echo $e->getMessage();
die();
}
// 接続を閉じる
$dbh = null;
操作後のテーブル
処理が正常に実行されると、テスト有希さんのageが28に更新されます。
もし途中でエラーが発生した場合はcatch文へ処理が移動し、rollBackメソッドによってデータベースが処理前の状態へ復帰します。
以上、SQLiteでのトランザクションでした。
こちらの記事は役に立ちましたか?
コメントありがとうございます!
運営の参考にさせていただきます。
ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。