我正在开发一个使用SQLite的多线程C#程序。我遇到了一个问题,有时运行SQLiteCommand.ExecuteNonQuery()来更新一些行时会抱怨"SQLite错误(5):数据库被锁定“。我知道发生这种情况是因为数据库在执行insert或update操作时被锁定,所以如果出现另一个修改DB的查询,那么第二个查询将出现this database is locked错误。因此,我正在尝试实现解决方法,但我不确定我应该如何做。
我正在尝试这样做,这样如果抛出数据库锁定错误,程序就会等待一段时间,然后再次尝试,直到它工作。但不知何故,没有捕获到异常,代码只是退出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)如何检测数据库是否被锁定错误发生。提前谢谢。
发布于 2017-11-13 12:37:58
如果您收到错误代码5 (busy),您可以使用立即事务来限制此错误代码。如果您能够开始一个即时事务,SQLite将保证您在提交之前不会收到busy错误。
还要注意,SQLite没有行级锁定。整个数据库都被锁定了。使用WAL期刊,您可以一个作者和多个读者。使用其他日志记录方法时,可以有一个写入器,也可以有多个读取器,但不能同时具有这两个读取器。
'SQLITE_BUSY‘上的SQLite文档
发布于 2021-03-18 21:09:30
为了检测Sqlite DB是否被锁定,我使用了来自Determine whether SQLite database is locked的方法,这里的想法是尝试获取锁并立即释放它,如果它没有失败,那么DB就没有被锁定。下面的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 )。
https://stackoverflow.com/questions/47256792
复制相似问题