データベースアプリケーションでは、エラーがなければコミット、エラーがあればロールバックという処理が頻繁に見られます。
たいていは次のようなコードになります。
var
transaction: TDBXTransaction;
begin
//トランザクションを開始する
transaction := SQLConnection1.BeginTransaction;
try
//SQLを実行する
SQLConnection1.Execute('insert into …');
//トランザクションをコミットする
SQLConnection1.CommitFreeAndNil(transaction);
except
//トランザクションをロールバックする
SQLConnection1.RollbackFreeAndNil(transaction);
raise;
end;
end;
トランザクションを使用するときのコードは、SQLを実行する箇所以外は同じ処理になります。
そこで共通部分をまとめて、次のように記述できるようにします。
begin
FTransactor.Perform(procedure
begin
SQLConnection1.Execute('insert into …');
end);
end;
SQLを実行する部分のコードを無名関数で渡すことができるようにしました。
無名関数を渡せるようにすると、自由度が高くて使い勝手がよくなります。
FTransactorはTTransactor型のメンバ変数です。
TTransactor型は次のようになります。
type
TTransactor = record
FSQLConnection: TSQLConnection;
constructor Create(SQLConnection: TSQLConnection);
procedure Perform(Proc: TProc);
end;
コンストラクタの引数でTSQLConnectionを渡します。
constructor TTransactor.Create(SQLConnection: TSQLConnection);
begin
FSQLConnection := SQLConnection;
end;
フォームのコンストラクタでは、FTransactorを生成しています。
procedure TForm1.FormCreate(Sender: TObject);
begin
FTransactor := TTransactor.Create(SQLConnection1);
end;
トランザクションのコミット・ロールバックを行うPerformメソッドは次のようになります。
procedure TTransactor.Perform(Proc: TProc);
var
transaction: TDBXTransaction;
begin
transaction := FSQLConnection.BeginTransaction;
try
Proc;
FSQLConnection.CommitFreeAndNil(transaction);
except
FSQLConnection.RollbackFreeAndNil(transaction);
raise;
end;
end;
引数Procで無名関数を受け取っています。
無名関数は便利ですね。
このTTransactor型は『実践テスト駆動開発 テストに導かれてオブジェクト指向ソフトウェアを育てる』でJavaで書かれていたコードを参考にしました。