PHP – pdoでMySQLへの変更をrollbackしたりするトランザクション

フレームワークに頼りきりだったので試しにPDOでトランザクションを書いてみた。全体的に動作させられるものを書いた方が誰かのためになりそうだったので、最小限のDB操作クラスを丸ごと作ってみたが、どっかおかしいところあれば教えてくだしあ。

まず以下のDatabaseクラスには

の3つの簡易的なものがくっついてる。

<?php
class Database
{
public $pdo;
public function __construct()
{
$with = function($s) { return $s; };
try {
$this->pdo = new PDO("mysql:host={$with(DB_HOST)};dbname={$with(DB_NAME)};charset={$with(DB_CHAR)}", DB_USER, DB_PASS, [PDO::ATTR_EMULATE_PREPARES => false]);
} catch (PDOException $e) {
exit('Database Error');
}
}
function transaction($callback) {
$this->pdo->beginTransaction();
try {
$callback();
$this->pdo->commit();
} catch (OriginalException $e) {
$this->pdo->rollBack();
throw $e;
}
}
function create_test($data)
{
extract($data, EXTR_SKIP);
$stmt = $this->pdo->prepare('INSERT INTO `table_test` (`name`, `age`) VALUES (:name, :age);');
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
$stmt->bindParam(':age', $age, PDO::PARAM_INT);
if ($stmt->execute()) {
return array_merge($data, ['id' => $this->pdo->lastInsertId()]);
} else {
throw new OriginalException();
}
}
}
# 本当はファイル分けたいけど今回は検証なのでここに置く!
class OriginalException extends Exception {}

このDatabaseクラスを使うと以下のようなコードでMySQLへのINSERTができる

<?php
$db = new Database();
$db->create_test(['name' => 'hoge1', 'age' => 10]);

そしてさっそくDatabaseクラスに作ったトランザクションを使ってみた例がこれ

<?php
try {
$db = new Database();
$db->transaction(function() use ($db) {
$db->create_test(['name' => 'hoge1', 'age' => 10]);
$db->create_test(['name' => 'hoge2', 'age' => 20]);
$db->create_test(['name' => 'hoge3', 'age' => 30]);
});
} catch (OriginalException $e) {
echo "失敗だったみたいなのでロールバックしてとりあえず停止";
exit;
}

3つの書き込みを行っているが、どれか一つで書き込みに失敗すれば、全体の書き込みはcommitされずroolbackされる。実際にrollbackされるのか確かめたければ特定のカラムの文字列を欠落させたINSERTを一つ実行してみれば確認できる。

便利なところはトランザクションでラップしている感じにしているところで、それぞれのcreate_test()が失敗すればExceptionを返すようになっているので、transaction()はExceptionを監視して問題なければcommit、Exceptionが一つでも発生すれば処理を中断してrallbackしてくれるという仕組みになっている。これによって一つずつの実行結果を受け取って都度rollback処理を書いたりする必要がない。

ちなみにPDO::beginTransactionなんだが元々がオートコミットモードなんだけど、これを使えばオフにできるんだそうだ。

オートコミットモードをオフにします。オートコミットモードがオフの間、 PDO オブジェクトを通じてデータベースに加えた変更は PDO::commit() をコールするまでコミットされません。 PDO::rollback() をコールすると、 データベースへの全ての変更をロールバックし、 オートコミットモードに設定された接続を返します。

PHP: PDO::beginTransaction - Manual

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA