LoginSignup
2
4

More than 1 year has passed since last update.

よく間違えて書かれるトランザクション処理について

Last updated at Posted at 2022-05-18

はじめに

自分が見てきたコードでよく間違えられて書かれるトランザクション処理をまとめました。
原因として多いのが、例外処理が正しく書けていないパターンです。

開発環境

  • PHP 7.4.12
  • CakePHP 4.2.5

NG集

  • ▼ NG例 ①

/** @var \Cake\Database\Connection $connection */
$connection = ConnectionManager::get('default');
try {
    // トランザクション開始
    $connection->begin();
    $this->Articles->save($saveData);
    $connection->commit();
} catch (Exception $e) {
    // キャッチされない
    $connection->rollback();
    echo $e->getMessage();
}
  • 〇 問題点
    • save()では例外を投げないため、Exceptionでキャッチすることができない。
  • ▼ NG例 ②

/** @var \Cake\Database\Connection $connection */
$connection = ConnectionManager::get('default');
try {
    // トランザクション開始
    $connection->transactional(function ($connection) use ($saveData) {
        return $this->Articles->save($saveData);
    });
} catch (Exception $e) {
    // キャッチされない
    echo $e->getMessage();
}
  • 〇 問題点
    • ConnectionManagerのtransactionalメソッドはfalse を返したら、ロールバックを発行して false を返すため、例外をcatchできない。(※トランザクション処理自体は正しい)
    • 例外を代入する変数には何も入らない。

OK集

  • ▼ OK例 ①

/** @var \Cake\Database\Connection $connection */
$connection = ConnectionManager::get('default');
try {
    // トランザクション開始
	$connection->begin();
	if ($this->Articles->save($saveData) === false) {
		throw new Exception('保存に失敗しました');
	}
	$connection->commit();
} catch (Exception $e) {
	$connection->rollback();
	echo $e->getMessage();
}
  • 〇 改善点

    • falseで判定して、例外を投げているため、Exceptionでキャッチが可能
  • ▼ OK例 ②

/** @var \Cake\Database\Connection $connection */
$connection = ConnectionManager::get('default');
try {
    // トランザクション開始
	$connection->transactional(function ($connection) use ($saveData) {
		$this->Articles->saveOrFail($saveData);
	});
} catch (\Cake\ORM\Exception\PersistenceFailedException $e) {
	echo $e->getMessage();
}
  • 〇 改善点
    • saveOrFail()により、PersistenceFailedExceptionを投げているため、再スローでキャッチが可能

補足

CakePHP4 transactionalについて
このコネクションインスタンスへのインターフェースに加えて、さらに begin/commit/rollback を 簡単にハンドリングする transactional() メソッドが提供されています。

  • 引数で渡されたクロージャーを実行します。
  • もしクロージャー内で例外が発生したら、ロールバックを発行して例外を再度 throw します。
  • クロージャーが false を返したら、ロールバックを発行して false を返します。
  • クロージャーが正常終了したら、トランザクションをコミットします。

CakePHP4 saveOrFailについて
このメソッドを使用すると、次の条件で Cake\ORM\Exception\PersistenceFailedException を投げます。

  • アプリケーションルールのチェックに失敗した場合
  • エンティティーにエラーが含まれている場合
  • 保存がコールバックによって中断された場合
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4