最近、SOY CMS内でポイントの様な価値あるデータをAさんからBさんに譲渡する

といった機能を良く書いていて、その際にトランザクションを利用する。


これらの処理はもちろんSOY CMS内にあるSOY2DAOクラスを利用していて、

それがかなり使いやすいので、書き方を書いておく。


SOY2DAOはDAOだけど、生のSQLをそのまま実行したい気分の時はそのまま書けるし、

生のSQLの実行結果をDAOのORマッパーの様に振る舞うこともできる優れもの!

SOY CMS/Shopのモジュール内でSQLを実行する

SOY2DAOでデータベースから値を取り出す

SOY2DAOでSQLを実行して、オブジェクトで返す




実際のコードを書く前にトランザクションについて触れておく。

よくある例として、Aさんの通帳からBさんの通帳に10000円を振り込むという処理を見てみる。


通帳から通帳へお金を移動する場合、

下記の処理が考えられる。


1. Aさんの通帳の残金をマイナス10000円する

2. Bさんの通帳の残金をプラス10000円する

3. Aさんの通帳にBさんへ10000円渡したことを記帳する

4. Bさんの通帳にAさんから10000円受け取ったことを記帳する


この4つの処理を実行し終わった時、Aさんの通帳からBさんの通帳へ10000円が移動したことになる。


さて、ここで、2の前にトラブルが起こったとしよう。

すると、Aさんの通帳から10000円が減ったにも関わらず、Bさんの通帳の残金は変わらず、

どちらの通帳にも記帳がないのでAさんのお金が減っていることをAさん自身はわからない。


この途中で処理が終わる問題が発生しないようにするのがトランザクションという機能で、

今回の処理に関して、1〜4までの処理がすべて行われない限り、データベースへの変更は行わない。

すべての処理が終了すれば各々のデータの変更を一斉に登録する。

※実際には1〜4のどこかで問題が発生したら、それまでの処理を取消す(ロールバック)


この処理により、

確実に安全に振り込み等のお金のやり取りを行うことができる様になる。




実際に、SOY2DAOでのトランザクションを書いてみる。

冒頭にあった例のAさんのポイントから○ポイントをBさんへプレゼントする機能を書いてみる。


$dao = new SOY2DAO();

//どこかの処理で失敗した場合はfalseにする
$successed = true;

//トランザクションを開始する
$dao->begin();

//Aさんのポイントを減らす
/** ここでAさんのポイントを調べて、○ポイント引いた数字を取得しておく **/
try{
	$dao->executeUpdateQuery("UPDATE soyshop_point SET …以下省略");
}catch(Exception $e){
	$successed = false;
}

//Bさんのポイントを増やす
/** ここでAさんのポイントを調べて、○ポイント足した数字を取得しておく **/
try{
	$dao->executeUpdateQuery("UPDATE soyshop_point SET …以下省略");
}catch(Exception $e){
	$successed = false;
}

//Aさんのポイントが減った履歴を残す
try{
	$dao->executeUpdateQuery("INSERT soyshop_point_history SET …以下省略");
}catch(Exception $e){
	$successed = false;
}

//Bさんのポイントが増えた履歴を残す
try{
	$dao->executeUpdateQuery("INSERT soyshop_point_history SET …以下省略");
}catch(Exception $e){
	$successed = false;
}

//すべての処理が問題なく終了すれば$successedはtrueになり、commitでトランザクションを終了する
$dao->commit();

$dao->begin()を実行した後、問題なければ$dao->commit();で終了する。

$dao->commit();しなければ、beginからcommitで囲った箇所の変更は受理されない。


サーバのリソースは余分に食うけど、これで一安心!