Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么';在我关闭应用程序之前,我的SQLite数据库不会添加数据吗?_Sqlite_Delphi_Firedac - Fatal编程技术网

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

为什么';在我关闭应用程序之前,我的SQLite数据库不会添加数据吗?,sqlite,delphi,firedac,Sqlite,Delphi,Firedac,我的Delphi应用程序使用FireDac和SQLite数据库。我注意到更新保存在一个日志文件中,数据库文件在我关闭应用程序之前不会真正更新 应用程序正在对数据库进行大量“批量更新”。每个单独的更新都在TFDQuery.StartTransaction中。。。提交对。尽管如此,似乎所有更新都保存在日志文件中,直到应用程序结束 try Query.Connection := FDConnection1; FDConnection1.Open; FDConnection1.StartTr

我的Delphi应用程序使用FireDac和SQLite数据库。我注意到更新保存在一个日志文件中,数据库文件在我关闭应用程序之前不会真正更新

应用程序正在对数据库进行大量“批量更新”。每个单独的更新都在TFDQuery.StartTransaction中。。。提交对。尽管如此,似乎所有更新都保存在日志文件中,直到应用程序结束

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;
如何在每批更新之后而不是在应用程序完成时强制SQLite更新数据库

我尝试将SQLite db更改为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在这方面正是我所需要的。

您使用的是
FDConnection1.StartTransaction
在此状态条件下,事务仍在内存(缓存)中,没有结束。因此,您需要使用
commit
命令结束事务,如
FDConnection1.commit

很可疑的是,“似乎所有更新都保存在日志文件中,直到应用程序结束”。SQLite3非常认真地编写数据——比我所知道的大多数DB引擎都要认真。检查一下

我怀疑你对日志文件的存在有些困惑。事务完成后,日志文件仍保留在磁盘上,以便进行任何新的写入操作。但是数据实际上是写在主文件中的

只需写入一些数据,然后在关闭应用程序之前杀死它(使用任务管理器)。然后重新打开文件(重新启动应用程序):我几乎可以肯定你会看到正确存储的数据


FireDAC使用默认日志模式“作弊”,以获得最佳性能。它使用了一些可能会让人困惑的默认值。如所述:将锁定模式设置为正常,以启用共享数据库访问。将Synchronous设置为Normal或Full以使提交的数据对其他人可见。

好的,我回到了基础知识,编写了一个测试应用程序,所有数据库活动仅限于通过单击按钮触发的单个过程。在该过程中,我使用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没有更新数据库。

谢谢您的响应。我已经有了FDConnection1.Commit-就在Exception块之前。对不起,Steve,删除了我对你文章的回答。你完全正确,是我的错。似乎是SQLLite的一个问题。请看:SQLLite驱动程序默认配置为提供高性能。查看“使用SQLite数据库”一节的位置4-6可能会有所帮助。如果不是alreadyDave,请将Options属性中的锁定模式设置为lmNormal-谢谢。我检查过,它被设置为lmNormal。这种行为甚至在中有记录。如果
locking_mode
设置为
EXCLUSIVE
,则在事务结束时不会删除回滚日志,这在FireDAC.Arnaud中是默认设置的-谢谢您。我现在觉得有点傻。我尝试了你的建议,并在调用“提交”后立即终止了我的应用程序。正如您所建议的,日志文件仍然存在,但数据已添加到数据库中。我被一个打开的浏览器窗口愚弄了,它显示了我的应用程序运行时日志文件的存在。Peter-谢谢你。我以前见过这种情况,但第二次阅读帮助我更好地理解了这一点。这种行为听起来像是在创建保存点。这似乎是在你已经有一笔交易未结的情况下开始交易的时候。我会寻找迷路的
StartTransaction
呼叫。或者你正在使用Wal模式,这是正常行为。Shawn,谢谢你的回复。我会仔细检查我的代码,看看是否是这样。Shawn,只是确认一下,WAL没有被使用。