我的Delphi应用程序正在使用FireDac和一个SQLite数据库。我注意到更新是保存在日志文件中的,而直到关闭我的应用程序,数据库文件才真正更新。
应用程序正在对数据库进行大量的“批处理更新”。每个单独的更新都在TFDQuery.StartTransaction ... TFDQuery.Commit对中。尽管如此,似乎所有更新都保留在日志文件中,直到应用程序结束。
如何强制SQLite在每批更新之后而不是在我的应用程序完成时更新数据库?
我尝试将SQLite数据库更改为WAL,但是发生了同样的事情。
尽管使用'StartTransaction'和'Commit',数据仍保留在日志中,直到应用程序结束。
try
Query.Connection := FDConnection1;
FDConnection1.Open;
FDConnection1.StartTransaction;
Query.SQL.Text := 'select 1 from t_Manufacturers where m_Name = ' + QuotedStr(ManString);
Query.Open;
if Query.RecordCount = 0 then begin
{ not found, so add }
Query.SQL.Text := 'insert into t_Manufacturers (m_Name, m_ManUID) values (:Name, null)';
Query.ParamByName('Name').AsString := ManString;
Query.ExecSQL;
{ save m_ManUID for logging }
Query.SQL.Text := 'select m_ManUID from t_Manufacturers where m_Name = ' + QuotedStr(ManString);
Query.Open;
end;
Result := Query.FieldByName(m_ManUID).AsInteger;
FDConnection1.Commit;
except
on E : EDatabaseError do begin
MessageDlg('Database error adding manufacturer: ' + E.Message, mtError, [mbOk], 0);
FDConnection1.Rollback;
end;
没有错误消息或问题。只要应用程序运行正常,数据库将按预期进行更新,因此我很高兴我的编程和SQL能够完全满足我的需求。
答案 0 :(得分:1)
“ 似乎所有更新都保留在日志文件中,直到应用程序结束,这是非常可疑的。” SQLite3对于写数据非常认真-比我所知道的大多数DB引擎都要认真。只需检查https://www.sqlite.org/atomiccommit.html
我怀疑您对日记文件的存在感到困惑。事务后,日志文件仍保留在磁盘上,准备进行任何新的写操作。但是数据实际上是写在主文件中的。
只需编写一些数据,然后在关闭应用程序之前将其杀死(使用任务管理器)。然后重新打开文件(重新启动应用程序):我几乎可以肯定您会看到数据已正确存储。
FireDAC使用默认的日记模式“欺骗”以获得最佳性能。它使用一些可能令人困惑的默认值。如FireDAC documentation所述:将LockingMode设置为Normal以启用共享数据库访问。将“同步”设置为“普通”或“完整”,使提交的数据对其他人可见。
答案 1 :(得分:0)
您正在使用FDConnection1.StartTransaction;
,在这种状态下,事务仍在内存(高速缓存)上,没有结束。因此,您需要使用commit
之类的FDConnection1.Commit;
命令结束交易。
答案 2 :(得分:0)
好的,我回到基础上来,编写了一个测试应用程序,所有数据库活动都被单击一个按钮触发了一个过程。在该过程中,我使用for循环向表中添加了多行。
for循环被 StartTransaction 和 Commit 调用包围。通过调试器中的代码运行,在第一次调用ExecSQL时创建日记文件。但是,在循环完成并调用了 Commit 之后,文件仍保留在该文件中。
仅在过程结束时调用 Close 时,才更新数据库并删除日记文件。
procedure TForm1.Button1Click(Sender: TObject);
var
Query : TFDQuery;
Index : Integer;
begin
FDConnection1.DriverName := 'SQLite';
FDConnection1.Params.Values['Database'] := 'C:\Testing\test.db';
FDConnection1.Open;
Query := TFDQuery.Create(nil);
Query.Connection := FDConnection1;
try
FDConnection1.StartTransaction;
for Index := 1 to 10 do begin
Query.SQL.Text := 'insert into Table1 (Name, IDNum) values (:Name, :IDNum)';
Query.ParamByName('Name').AsString := 'Test_Manufacturer_' + IntToStr(Index);
Query.ParamByName('IDNum').AsInteger := Index;
Query.ExecSQL;
end;
FDConnection1.Commit;
except
on E : EDatabaseError do begin
MessageDlg('Database error adding manufacturer: ' + E.Message, mtError, [mbOk], 0);
FDConnection1.Rollback;
end;
end;
Query.Destroy;
FDConnection1.Close;
end;
我怀疑我的应用程序中打开了另一个与数据库的连接,这可能会停止更新,直到应用程序关闭。但是,我仍然不明白为什么对Commit的调用没有在事务块的末尾更新数据库。