データベーストランザクションはデータベースマネジメントシステムもしくは似たようなシステムとのインタラクションのユニットです。トランザクションは完結させるか停止するかどちらかでなければならず他のトランザクションから独立した整合性と信頼性のある方法で扱われます。理想的には、データベースシステムはそれぞれのトランザクションに対してACID(Atomicity、Consistency、Isolation、とDurability)プロパティのすべてを保証します。
Doctrineにおいてデフォルトではすべてのオペレーションはトランザクションにラップされます。Doctrineが内部で動作する方法について注目すべきことは次の通りです:
最初に新しいトランザクションを始める必要があります:
$conn->beginTransaction();
次に実行されているクエリになるオペレーションをいくつか実行します:
$user = new User();
$user->name = 'New user';
$user->save();
$user = Doctrine_Core::getTable('User')->find(5);
$user->name = 'Modified user';
$user->save();
commit()メソッドを使用することですべてのクエリをコミットできます:
$conn->commit();
Doctrine DBALでトランザクションを簡単にネストできます。ネストされたトランザクションを実演するシンプルな例を示す下記のコードを確認しましょう。
最初にsaveUserAndGroup()という名前のPHP関数を作ってみましょう:
function saveUserAndGroup(Doctrine_Connection $conn, User $user, Group $group)
{
$conn->beginTransaction();
$user->save();
$group->save();
$conn->commit();
}
別のトランザクション内部でメソッドを利用します:
try {
$conn->beginTransaction();
saveUserAndGroup($conn,$user,$group);
saveUserAndGroup($conn,$user2,$group2);
saveUserAndGroup($conn,$user3,$group3);
$conn->commit();
} catch(Doctrine_Exception $e) {
$conn->rollback();
}
saveUserAndGroup()への3つの呼び出しがトランザクションでラップされ、それぞれの関数呼び出しは独自のネストされたトランザクションを始めることに注目してください。
Doctrineはトランザクションのセーブポイントをサポートします。このことは名前有りのトランザクションを設定してこれらをネストできることを意味します。
Doctrine_Transaction::beginTransaction($savepoint)は$savepointの名前で名付けられたトランザクションセーブポイントを設定し、現在のトランザクションが同じ名前のセーブポイントを持つ場合、古いセーブポイントは削除され新しいものが設定されます。
try {
$conn->beginTransaction();
// 何らかのオペレーションをここで行う
// mysavepointと呼ばれる新しいセーブポイントを作成する
$conn->beginTransaction('mysavepoint');
try {
// 何らかのオペレーションをここで行う
$conn->commit('mysavepoint');
} catch(Exception $e) {
$conn->rollback('mysavepoint');
}
$conn->commit();
} catch(Exception $e) {
$conn->rollback();
}
Doctrine_Transaction::rollback($savepoint)はトランザクションを名前付きのセーブポイントにロールバックします。セーブポイントの後で現在のトランザクションが列に行った修正はロールバックで取り消しになります。
例えばMysqlの場合、セーブポイントの後でメモリーに保存された列のロックを開放しません。
名前付きのセーブポイントの後で設定されたセーブポイントは削除されます。
Doctrine_Transaction::commit($savepoint)は現在のトランザクションのセーブポイントのセットから名前付きのセーブポイントを削除します。
コミットを実行するもしくはセーブポイントの名前パラメータ無しでロールバックが呼び出されている場合現在のトランザクションのすべてのセーブポイントは削除されます。
try {
$conn->beginTransaction();
// ここで何らかのオペレーションを行う
// mysavepointと呼ばれる新しいセーブポイントを作成する
$conn->beginTransaction('mysavepoint');
// ここで何らかのオペレーションを行う
$conn->commit(); // すべてのセーブポイントを削除する
} catch(Exception $e) {
$conn->rollback(); // すべてのセーブポイントを削除する
}
トランザクションの独立性レベル(isolation level)はデフォルトのトランザクションのビヘイビアを設定します。'独立性レベル'という名前が示すように、設定がそれぞれのトランザクションの独立性の程度、もしくはトランザクション内部でどんな種類のロックがクエリに関連付けされているかを決定します。利用できるレベルは4つあります(厳密性の昇順):
transactionモジュールを取得するには、次のコードを使います:
$tx = $conn->transaction;
独立性レベルをREAD COMMITTEDに設定する:
$tx->setIsolation('READ COMMITTED');
独立性レベルをSERIALIZABLEに設定する:
$tx->setIsolation('SERIALIZABLE');
ドライバの中には(Mysqlのように)現在の独立性レベルの取得をサポートするものがあります。次のようにできます:
$level = $tx->getIsolation();
トランザクションはデータベースの質と一貫性を保証する偉大な機能です。トランザクションを理解したのでイベントサブフレームワークについて学ぶ準備ができています。
イベントサブフレームワークはDoctrineのコアメソッドにフックを入れることを可能にする偉大な機能でコアコードを一行も修正せずに内部機能のオペレーションを変更します。