由fireDAC访问的SQLite中的表锁

时间:2017-11-01 12:30:16

标签: sqlite delphi firedac delphi-10.2-tokyo

我正在努力将一组paradox表移植到SQLite。为此,我创建了一个测试应用程序,模拟(稍微)当前的使用场景:多个用户访问同一个DB文件并同时执行读写操作。

应用程序非常简单:它将启动多个线程,每个线程创建一个连接,打开一个表并随机读取,更新或插入表格内。

几乎立即,应用程序遇到“数据库表已锁定”错误。我尝试了几件事来尝试解决它,但似乎没有任何效果。我做错了什么?

以下是线程内部的代码:

procedure testDB(TargetFolder: string);
var
  Conn: TFDConnection;
  Table: TFDTable;
  i: Integer;
begin
  randomize;
  Conn := TFDConnection.Create(nil);
  try
    Conn.DriverName := 'SQLite';
    Conn.LoginPrompt := false;
    Conn.Params.clear;
    Conn.Params.Database := TPath.Combine(TargetFolder, 'testDB.sdb');
    Conn.Params.Add('DriverID=SQLite');
    // all this is the result of several attemp to fix the table locking error. none worked

    Conn.Params.Add('LockingMode=Normal');
    Conn.Params.Add('Synchronous=Normal');
    Conn.UpdateOptions.UpdateMode := TUpdateMode.upWhereAll;
    Conn.UpdateOptions.LockWait := True;
    Conn.UpdateOptions.LockMode := TFDLockMode.lmPessimistic;
    Conn.UpdateOptions.LockPoint := TFDLockPoint.lpImmediate;
    Conn.UpdateOptions.AssignedValues := [uvLockMode,uvLockPoint,uvLockWait];
    Conn.Open();
    Conn.ExecSQL('CREATE TABLE IF NOT EXISTS ''test'' (''ID''   INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,''data1'' TEXT NOT NULL,''data2'' INTEGER NOT NULL)');
    Table := TFDTable.Create(nil);
    try
      table.Connection := Conn;
      while True do
      begin
        case Trunc(Random(10)) of
          0..3:
          begin
            table.Open('test');
            try
              if table.Locate('data1', 'name'+intToStr(Trunc(Random(10))),[TLocateOption.loCaseInsensitive]) then
              begin
                table.Edit;
                table.FieldByName('data2').AsInteger := table.FieldByName('data2').AsInteger + 1;
                table.Post;
              end;
            finally
              table.close;
            end;
          end;
          4..8:
          begin
            table.Open('test');
            try
              i := Trunc(Random(10));
              if not table.Locate('data1', 'name'+ i.ToString,[TLocateOption.loCaseInsensitive]) then
              begin
                table.AppendRecord([null, 'name'+ i.ToString, 0]);
              end;
            finally
              table.close;
            end;
          end
        else
          break;
        end;
      end;
    finally
      FreeAndNil(Table);
    end;
  finally
    FreeAndNil(Conn);
  end;
end;

1 个答案:

答案 0 :(得分:2)

感谢Victoria,我设法找到了正确的参数。

  Conn := TFDConnection.Create(nil);
  try
    Conn.DriverName := 'SQLite';
    Conn.LoginPrompt := false;
    Conn.Params.clear;
    Conn.Params.Database := TPath.Combine(TargetFolder, 'testDB.sdb');
    Conn.Params.Add('DriverID=SQLite');
    Conn.Params.Add('SharedCache=False');
    Conn.Params.Add('LockingMode=Normal');
    Conn.Params.Add('Synchronous=Normal');
    Conn.UpdateOptions.LockWait := True;
    Conn.Open();

再次感谢