我正在开发一个使用 SQLite 的多线程 C# 程序。我遇到一个问题,有时运行 SQLiteCommand.ExecuteNonQuery() 来更新某些行会抱怨“SQLite 错误 (5):数据库已锁定”。我知道发生这种情况是因为数据库在插入或更新时被锁定,因此如果出现另一个修改数据库的查询,第二个查询将出现此数据库被锁定错误。所以我正在尝试实施解决方法,但我不确定应该如何做。
我试图做到这一点,以便如果抛出数据库锁定错误,则程序会等待一段时间并再次尝试,直到它起作用。但不知何故,没有捕获异常,并且代码只是退出 try-catch 块,即使数据库锁定消息仍然打印在调试输出中。我不完全确定 SQL 查询是否被拒绝或接受。
我也尝试过使用 TransactionScope,从那时起我就没有遇到过数据库被锁定的情况,但是由于问题的随机性,我无法 100% 确定 TransactionScope 是否真正解决了问题,或者它是否只解决了问题程度,或者如果没有,到目前为止我很幸运。
SQLiteConnection connection = new SQLiteConnection("Data Source=DB.db;Version=3;");
connection.Open();
SQLiteCommand command = connection.CreateCommand();
command.commandText = inputQuery;
try
{
command.executeNonQuery();
}
catch (SQLiteException sqle)
{
Debug.WriteLine("Database error: " + e.Message);
return false;
}
catch (Exception e)
{
Debug.WriteLine("Database error: " + e.Message);
return false;
}
finally
{
connection.Close();
}
所以我真的很希望有人帮助我找出 1)如何消除数据库被锁定问题或 2)如何检测数据库是否被锁定错误发生。提前致谢。
为了检测 Sqlite DB 是否被锁定,我使用了以下方法判断SQLite数据库是否被锁定 https://stackoverflow.com/questions/57744538/determine-whether-sqlite-database-is-locked#这里的想法是尝试获取锁并立即释放它,如果没有失败则数据库没有被锁定。
以下 C# 代码对我有用:
public bool IsDatabaseLocked(string dbPath)
{
bool locked = true;
SQLiteConnection connection = new SQLiteConnection($"Data Source={dbPath};Version=3;");
connection.Open();
try
{
SQLiteCommand beginCommand = connection.CreateCommand();
beginCommand.CommandText = "BEGIN EXCLUSIVE"; // tries to acquire the lock
// CommandTimeout is set to 0 to get error immediately if DB is locked
// otherwise it will wait for 30 sec by default
beginCommand.CommandTimeout = 0;
beginCommand.ExecuteNonQuery();
SQLiteCommand commitCommand = connection.CreateCommand();
commitCommand.CommandText = "COMMIT"; // releases the lock immediately
commitCommand.ExecuteNonQuery();
locked = false;
}
catch(SQLiteException)
{
// database is locked error
}
finally
{
connection.Close();
}
return locked;
}
然后,当您确定数据库是否被锁定时,您可以等待它被解锁:
public async Task WaitForDbToBeUnlocked(string dbPath, CancellationToken token)
{
while (IsDatabaseLocked(dbPath))
{
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
}
或者在运行查询之前将取消消息发送到其他线程(例如通过 CancellationTokenSource)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)