データベースに対して複雑なスクリプトを実行するためのツールを作成する必要があります。
いくつかの理由で、DBのトランザクション動作に依存することはできませんが、独自のトランザクションシステムを実装する必要があります。
私が試しているアプローチは、コマンドパターンの助けを借りています(私の場合はもっと複雑です、ここでは議論のために簡略化されたバージョンを置きます):
type
IMyCommand = interface(IInterface)
procedure Execute();
procedure Undo();
end;
type
TSQLCommand = class (TInterfacedObject, IMyCommand)
private
FDBConnection: TDBConnection;
FDBQuery: TDBQuery;
FExecuteSQL: string;
FUndoSQL: string;
FExecuted: boolean; // set to True as the command has been executed
public
procedure Execute;
procedure Undo;
procedure Prepare(aExecuteSQL, aUndoSQL: string);
constructor Create(aDBConnection: TDBConnection);
destructor Destroy; override;
end;
アクションのセットを作成します。すべてのアクションに対して、「実行」および「元に戻す」SQLステートメントを渡します。例:
準備の呼び出しは次のようになります。
Prepare('INSERT INTO TESTTABLE (ID, DATA) VALUES (15, 'Hello')',// aExecuteSQL
'DELETE FROM TESTTABLE WHERE ID = 15'); //aUndoSQL
だからどういうわけか私は非常に小さな変更を加えています(単一の単純な行の挿入、単一の行の更新など)、すべての変更に対して「元に戻す」は非常に明白です。
コマンドオブジェクトのスタックを(おそらくTObjectStackコレクションを使用して)準備し、Executeメソッドを一度に1つのコマンドで呼び出し、実行時にFExecutedをTrueに設定して、コンポーネントをディスクに保存します。
ですから、私がやりたいのはすべてのスクリプトを実行することですが、何かがうまくいかない場合を管理したいと思います。
何か問題が発生した場合は、最後から最初にUndoメソッドを呼び出すまでのすべてのコマンドを実行したいと思います。もちろん、これを行う前に、コンポーネントをディスクから復元できる必要があります(障害がハードウェア障害である場合、障害がすでにメモリにスタックを持っている別の理由である場合、undo1コマンドを簡単に呼び出すことができます時間)。
注:DBトランザクションの動作に依存できない主な理由は、大きなBLOBも挿入する必要があり、すべてのBLOBがインターネットからダウンロードされてから挿入されるため、すべてをコミットしたいため、トランザクションを永久に開いたままにすることはできません。データベースへの小さな変更。私がblobで行うことは、1つをダウンロードし、それを挿入し、次にダウンロードし、それを挿入することです...
だから私の質問は:私のオブジェクトをディスクに永続化する方法を提案できますか?私はDelphi2009を持っているので、1つのオプションは、TInterdacedPersistentを作成し、コンポーネントをストリーミングしてからファイルに保存することです。とにかく、この方法では、余分な複雑さを伴う多くのファイルがありますが、単一のファイルが望ましいです。提案してもらえますか?
編集:Delphi 2009ではTObjectStackにバグがあることに気づきました(Popは正しいタイプを返さない)ので、TObjectStackでも同じことができます。