我需要创建一个工具来执行针对数据库的复杂脚本。
出于几个原因,我不能依赖数据库事务行为,但我需要实现自己的事务系统。
我正在尝试的方法是在命令模式的帮助下(我的情况更复杂,这里我提出了一个简化版本供讨论):
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可能是:
Prepare('INSERT INTO TESTTABLE (ID, DATA) VALUES (15, 'Hello')',// aExecuteSQL
'DELETE FROM TESTTABLE WHERE ID = 15'); //aUndoSQL
所以不知怎的,我正在进行非常小的更改(比如插入一个简单的行,更新单行,......),对于每次更改,“撤消”都非常明显。
我将准备一堆命令对象(可能使用TObjectStack集合),并一次调用Execute方法一个命令,当执行一个命令时,我将FExecuted设置为True,并将组件保存到磁盘。
所以我要做的就是运行所有脚本,但我想管理出现问题的情况。
如果出现问题,我想执行从最后到第一次调用Undo方法的所有命令。当然在这之前我需要能够从磁盘恢复组件(如果故障是硬件故障,如果故障是另一个原因我已经在内存中有堆栈,我可以很容易地调用一个命令时间)。
注意:我不能依赖数据库事务行为的主要原因是我需要插入大blob,并且每个blob都是从Internet下载然后插入的,所以我不能让事务永远打开因为我想要将每个小的更改提交到数据库。我用blob做的是下载一个,插入,下载,插入,...
所以我的问题是:你能建议一种方法来坚持磁盘我的对象吗?我有Delphi 2009,所以一个选项是创建一个TInterdacedPersistent并将组件保存到流然后保存到文件,无论如何,这样我会有很多文件,有额外的complicatinos,而我更喜欢单个文件。你能建议吗?
编辑:我意识到TObjectStack在Delphi 2009中是错误的(Pop没有返回正确的类型),所以使用TObjectStack也可以做到这一点。
答案 0 :(得分:3)
我看不到比使用事务更好的方法,因为Andrei K.提到你的实现不安全,因此使用StartTransaction,Commit和Rollback是必须的!