トランザクションの処理を簡潔に書けるようにしてみた

データベースアプリケーションでは、エラーがなければコミット、エラーがあればロールバックという処理が頻繁に見られます。

たいていは次のようなコードになります。

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で書かれていたコードを参考にしました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください