在关闭应用程序之前,为什么我的SQLite数据库不添加数据?

时间:2019-08-19 09:46:06

标签: sqlite delphi firedac

我的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能够完全满足我的需求。

3 个答案:

答案 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的调用没有在事务块的末尾更新数据库。