Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

PHP辞典

  1. トップページ
  2. PHP辞典
  3. PDO::beginTransaction() / commit() / rollBack()

PDO::beginTransaction() / commit() / rollBack()対応: PHP 5(2004)

トランザクションは、複数のSQL操作をひとまとまりの処理として実行する仕組みです。途中でエラーが発生した場合にすべての操作を取り消し、データの整合性を保つことができます。

構文
// トランザクションを開始します。
$pdo->beginTransaction();

// トランザクションを確定します。
$pdo->commit();

// トランザクションを取り消します。
$pdo->rollBack();

// トランザクションが進行中かを確認します。
$pdo->inTransaction();
メソッド一覧
メソッド概要
PDO::beginTransaction()トランザクションを開始します。自動コミットが無効になり、『commit()』または『rollBack()』を呼ぶまで変更が確定しません。
PDO::commit()トランザクション内のすべての操作を確定してデータベースに反映します。
PDO::rollBack()トランザクション内のすべての操作を取り消し、開始前の状態に戻します。
PDO::inTransaction()現在トランザクションが進行中であれば『true』を返します。
サンプルコード
<?php
// 基本的なトランザクション処理です。
try {
	$pdo->beginTransaction();

	// 送金元の残高を減らします。
	$stmt = $pdo->prepare("UPDATE accounts SET balance = balance - :amount WHERE id = :id");
	$stmt->execute([':amount' => 10000, ':id' => 1]);

	// 送金先の残高を増やします。
	$stmt = $pdo->prepare("UPDATE accounts SET balance = balance + :amount WHERE id = :id");
	$stmt->execute([':amount' => 10000, ':id' => 2]);

	$pdo->commit(); // すべて成功した場合に確定します。
	echo "送金が完了しました。";
} catch (PDOException $e) {
	$pdo->rollBack(); // エラー発生時はすべて取り消します。
	echo "送金に失敗しました: " . $e->getMessage();
}

// 注文処理の実例です。注文と在庫更新を一括で処理します。
try {
	$pdo->beginTransaction();

	// 注文を登録します。
	$stmt = $pdo->prepare("INSERT INTO orders (user_id, product_id, quantity) VALUES (:user_id, :product_id, :qty)");
	$stmt->execute([':user_id' => 1, ':product_id' => 100, ':qty' => 2]);
	$orderId = $pdo->lastInsertId();

	// 在庫を減らします。
	$stmt = $pdo->prepare("UPDATE products SET stock = stock - :qty WHERE id = :id AND stock >= :qty");
	$stmt->execute([':qty' => 2, ':id' => 100]);

	// 在庫不足の場合はロールバックします。
	if ($stmt->rowCount() === 0) {
		$pdo->rollBack();
		echo "在庫が不足しています。";
	} else {
		$pdo->commit();
		echo "注文ID: " . $orderId . " を受け付けました。";
	}
} catch (PDOException $e) {
	if ($pdo->inTransaction()) {
		$pdo->rollBack(); // トランザクションが進行中の場合のみロールバックします。
	}
	echo "注文処理に失敗しました: " . $e->getMessage();
}

// inTransaction() で状態を確認します。
var_dump($pdo->inTransaction()); // トランザクション外では『bool(false)』と出力されます。
$pdo->beginTransaction();
var_dump($pdo->inTransaction()); // トランザクション中は『bool(true)』と出力されます。
$pdo->rollBack();

// 大量データの一括挿入をトランザクションで高速化します。
$users = [
	['name' => '田中一郎', 'email' => 'tanaka@example.com'],
	['name' => '鈴木二郎', 'email' => 'suzuki@example.com'],
	['name' => '高橋三郎', 'email' => 'takahashi@example.com'],
];

try {
	$pdo->beginTransaction();
	$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
	foreach ($users as $user) {
		$stmt->execute([':name' => $user['name'], ':email' => $user['email']]);
	}
	$pdo->commit(); // まとめてコミットすることで大幅に高速化されます。
	echo count($users) . "件のユーザーを登録しました。";
} catch (PDOException $e) {
	$pdo->rollBack();
	echo "一括登録に失敗しました: " . $e->getMessage();
}
概要

トランザクションは、複数のデータベース操作をアトミックに実行するための仕組みです。送金処理のように複数のテーブルを更新する場合、トランザクションを使わないと途中でエラーが発生した際にデータの不整合が生じます。必ず『beginTransaction()』で開始し、成功時に『commit()』、失敗時に『rollBack()』を呼んでください。

例外処理の『catch』ブロックでは、ロールバック前に『inTransaction()』で確認するのが安全です。既にロールバック済みの状態で再度『rollBack()』を呼ぶとエラーになるためです。

大量のINSERT文を実行する場合もトランザクションが有効です。自動コミットモードでは1件ごとにコミットが走りますが、トランザクションでまとめると大幅に高速化できます。データベース接続は『new PDO()』で行い、SQLの実行は『PDO::prepare()』を使用してください。例外処理の詳細は『try / catch』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。