当应用程序安装在programFiles中时,如何解决[FireDAC][Phys][SQLite]错误:无法打开数据库文件?

问题描述 投票:0回答:2

我使用 Firedac 开发了一个工具,数据库为 SQLite。

完成项目并制作安装程序(InnoSetup)后,我收到错误

[FireDAC][Phys][SQLite]错误:无法打开数据库文件

当我启动应用程序时(双击)。

这是我使用的连接参数

constructor TDbInteract.Create(const aDatabasePath: string; const aOnNeedCredentials: TOnNeedCredentials);
var
  aParams: array of string;
begin
  if not TFile.Exists(aDatabasePath) then
    raise Exception.Create('Database file not found');

  aParams := ['DriverID=SQLite',
              'Database=' + aDatabasePath,
              'OpenMode=CreateUTF16',
              'LockingMode=Normal',
              'JournalMode=WAL',
              'StringFormat=Unicode',
              'Synchronous=Full',
              'UpdateOptions.LockWait=True',
              'BusyTimeout=30000',
              'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];
  InitiateResource(aParams, aOnNeedCredentials);
end;

procedure TDbInteract.InitiateResource(const aParams: array of string; const aOnNeedCredentials: TOnNeedCredentials);
var
  I: Integer;
  Credentials: TStringDynArray;
begin
  FRowsAffected := 0;
  FIsForeignKeyHonored := True;
  FOwnsResultDataSets := True;
  FDataSetContainer := TDataSetContainer.Create(nil);

  FConnection := TFDConnection.Create(nil);
  try
    for I := Low(aParams) to High(aParams) do
    begin
      FConnection.Params.Add(aParams[I]);
    end;

    if Assigned(aOnNeedCredentials) then
    begin
      aOnNeedCredentials(Self, Credentials);

      for I := Low(Credentials) to High(Credentials) do
      begin
        FConnection.Params.Add(Credentials[I]);
      end;
    end;

    FConnection.Open;
  except
    raise;
  end;
end;

**发现的问题:

  1. 我在某处读到(不记得我所在的页面),SQLite 引擎需要对其要写入的目录进行完全锁定。这就是问题所在。我如何以调用者身份运行该工具,并且我的帐户是管理员,所以这不是问题。我也有用 C# 编写的相同工具,但这个问题从未发生过。

我找到的解决方案:

  1. 以管理员身份运行该工具
  2. 请勿将该工具安装在 ProgramFiles 目录中

我真的不喜欢这些解决方案。并想从程序文件目录运行我的工具,因为它是一个更大项目的一部分。

注意:数据库文件位于programdata目录中。它是由工具创建的(这有效)。

编辑:我刚刚尝试将数据库文件放入

C:\Users\Nacereddine\AppData\Roaming\MyTool
,当该工具安装在
C:\Program Files (x86)\MyTool

时,我仍然遇到同样的问题

这就是我创建数据库文件的方式

class procedure TDbInteract.CreateSQLiteDb(const aDatabasePath: string; const aTables: TStringDynArray);
var
  I: Integer;
  aParams: array of string;
  aConnection: TFDConnection;
begin
  aParams := ['DriverID=SQLite',
              'Database=' + aDatabasePath,
              'OpenMode=CreateUTF16',
              'LockingMode=Normal',
              'JournalMode=WAL',
              'StringFormat=Unicode',
              'Synchronous=Full',
              'UpdateOptions.LockWait=True',
              'BusyTimeout=30000',
              'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];

  aConnection := TFDConnection.Create(nil);
  try
    for I := Low(aParams) to High(aParams) do
    begin
      aConnection.Params.Add(aParams[I]);
    end;

    aConnection.Open();

    for I := Low(aTables) to High(aTables) do
    begin
      aConnection.ExecSQL(aTables[I]);
    end;
  finally
    aConnection.Close;
    aConnection.Free;
  end;
end;

注意:我不知道这是否有什么区别,但 Db 文件已加密。

delphi firedac delphi-10.2-tokyo
2个回答
1
投票

抱歉给大家带来麻烦了。

问题是我们在 ProgramFiles 中安装了一个与该工具一起安装的本地化数据库文件。

使我从调查中排除这一点的是,当打开此文件时,我将

OpenMode
设置为
ReadOnly

FConnection.Params.Add('OpenMode=ReadOnly');

但正如我之前在我的问题中所说,SQLite 引擎需要完全访问包含 db 文件的文件夹,因此它对其执行锁定(仍然没有找到我读到的页面)。

我通过尝试开放模式并每次调试该工具来检查这一点。 一旦我更改了文件和目录的权限,错误就消失了。

最后我决定将本地化文件与主数据库文件一起移动到programData目录中,一切都很好。

我意识到(谢谢@Ken和@David)programData目录也需要管理员权限才能写入,因此我将把数据库文件移动到更合适的目录(即用户)。

此问题的有用之处在于,即使您使用

OpenMode=ReadOnly
连接到 Sqlite db 文件,您仍然需要对该文件的路径进行写访问。


0
投票

我遇到了同样的问题: [FireDAC][Phys][SQLite] 数据库已锁定

可以解决。 在 Objectinspector (Delphi-GUI) 中设置 TFDQuery.Active=false 并设置 TFDConnection.Connected=false, 否则Delphi-GUI已经打开数据库,当你运行程序时,程序只能以读取模式打开数据库。

在程序中打开数据库,如下所示:

procedure TForm1.FormCreate(Sender: TObject);
begin
   TFDConnection.Connected:=true;
   TFDQuery.Active:=true;
end;
© www.soinside.com 2019 - 2024. All rights reserved.