Sqlite3の処理について、教えてください。Delphiは 12 29.0.52631.8427 Win10 です。
デスク上のSqliteのDBからメモリ上にBackupし、Backupを更新した後、デスク上のSqliteのDBに書き戻す処理をしたいです。
下記において、Detachの行で、「プロジェクト PrgAAAA.exe は例外クラス ESQLiteNativeException (メッセージ '[FireDAC][Phys][SQLite] ERROR: database DisckDB is locked')を送出しました。」が発生し困っています。
省略・単純化をしてますが、流れは次のとおりです。
//*******
// FDコネクション1のセット
FDConnection1.Connected := False;
FDConnection1.DriverName := 'SQLite';
FDConnection1.Params.Database := ':memory:';
//DBからメモリー上のSqliteにコピー
FDSQLiteBackup1.DriverLink := FDPhysSQLiteDriverLink1;
FDSQLiteBackup1.Database := SauceDataBaseFileName(); //SauceDataBaseFileName()はデスク上のデータベース名
FDSQLiteBackup1.DestDatabaseObj := FDConnection1.CliObj;
FDSQLiteBackup1.Backup;
FDConnection1.Connected := True;
//[:memory:]に対して更新処理
//省略
//処理完了後 [:memory:]から、DisckDBに書き戻し
//Attach
FDConnection1.ExecSQL('Attach ' + SauceDataBaseFileName().QuotedString(#39) + ' as DisckDB');
//処理 AAA
FDQuery1.SQL.Clear;
FDQuery1.SQL.Add('Delete From DisckDB.TableAAA');
FDConnection1.StartTransaction;
try
FDQuery1.ExecSQL;
FDConnection1.Commit;
except
FDConnection1.Rollback;
end;
//処理 BBB
FDQuery1.SQL.Clear;
FDQuery1.SQL.Add('Insert Into DisckDB.TableAAA Select * from TableAAA');
FDConnection1.StartTransaction;
try
FDQuery1.ExecSQL;
FDConnection1.Commit;
except
FDConnection1.Rollback;
end;
//Detach
FDConnection1.ExecSQL('Detach DisckDB');
//*****
最後の、 Detach処理で「プロジェクト PrgAAAA.exe は例外クラス ESQLiteNativeException (メッセージ '[FireDAC][Phys][SQLite] ERROR: database DisckDB is locked')を送出しました。」が発生します。
Delete、Insert処理ともCommitされ、DB Browser for SQLitewからデスク上のDBを確認すると、 [:memory:]から、DisckDBにコビーが成功していることも確認できます。また、lockedされてはいません。
「//処理 AAA」と「//処理 BBB」省いて、Attachの直後にDetachをした場合は、エラーは発生しません。
また、試しに、 Delete Insert (処理 AAAと 処理 BBB)に替えて、下記のようにSelect文でOpen,Closeしただけでも、Detachでエラーが発生します。
FDQuery1.SQL.Clear;
FDQuery1.SQL.Add('Select * from DisckDB.TableAAA');
FDQuery1.Open;
FDQuery1.Close;
Detachの前に必要な処理があるのでしょうか??。
よろしくお願いします。
あまりわかっていないのですいません。
SQLiteのトランザクション動作はデフォルトで遅延だそうです。
なので、
FDConnection1.Commit;
としても、即時実行して完了しているわけではないのでInsert文が未だ実行中の為テーブルはロックされたままなのではないかと思います。
以下の(a)又は(b)を試すのは如何でしょうか。
(a)接続を閉じると自動的にdetachされるので
FDConnection1.ExecSQL('Detach DisckDB'); の行を消す
(b)パラメータに
sqlite_use_immediate_transaction=1
を追加して即時実行させる
FDConnection1.Params.Add('sqlite_use_immediate_transaction=1');
外していたらすいません。
mamさん ありがとうございました。
結果としては、解決しました。
ただ、原因は特定できず、すっきりしません。
Sqliteは、データベースファイル名が「123.Sqlite」の場合、ロックされると「123.Sqlite-journal」が作成されます。
追跡したところ、-journalファイルは、前述の例では FDQuery1.ExecSQL によって生成され、 FDConnection1.Commitで、消滅してます。
また、単純なselect文では当然-journalは生成されず、ロックも発生しません。それでも、detachでDB is locked エラーが発生します。
どうも、ロックされているかどうかではなく、別に原因があるような気がします。
過去のプログラムでは、FDConnection1.ExecSQLでのAttach、Detachは問題は発生してませんでしたので、ますます原因不明です。
今回解決した方法は、試行錯誤で、
「FDConnection1.ExecSQL('Detach DisckDB');」を
「FDQuery1.ExecSQL('Detach DisckDB');」に替えたところ、エラーが発生しなくなりました。
どうしてこれで解決するのか理解できてませんが、先に進めそうです。
皆さん、お騒がせしました。