首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C# -如何检测SQLite DB是否已锁定?

C# -如何检测SQLite DB是否已锁定?
EN

Stack Overflow用户
提问于 2017-11-13 11:45:36
回答 2查看 2.5K关注 0票数 2

我正在开发一个使用SQLite的多线程C#程序。我遇到了一个问题,有时运行SQLiteCommand.ExecuteNonQuery()来更新一些行时会抱怨"SQLite错误(5):数据库被锁定“。我知道发生这种情况是因为数据库在执行insert或update操作时被锁定,所以如果出现另一个修改DB的查询,那么第二个查询将出现this database is locked错误。因此,我正在尝试实现解决方法,但我不确定我应该如何做。

我正在尝试这样做,这样如果抛出数据库锁定错误,程序就会等待一段时间,然后再次尝试,直到它工作。但不知何故,没有捕获到异常,代码只是退出try-catch块,即使数据库锁定消息仍然会在调试输出中打印出来。我不能完全确定SQL查询是被拒绝还是被接受。

我也尝试过使用TransactionScope,从那时起我就再也没有遇到过数据库被锁的事情,但由于这个问题的随机性,我不能100%确定TransactionScope是否真的解决了这个问题,或者它只在一定程度上解决了这个问题,或者它没有解决这个问题,到目前为止我只是很幸运。

代码语言:javascript
复制
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)如何检测数据库是否被锁定错误发生。提前谢谢。

EN

回答 2

Stack Overflow用户

发布于 2017-11-13 12:37:58

如果您收到错误代码5 (busy),您可以使用立即事务来限制此错误代码。如果您能够开始一个即时事务,SQLite将保证您在提交之前不会收到busy错误。

还要注意,SQLite没有行级锁定。整个数据库都被锁定了。使用WAL期刊,您可以一个作者和多个读者。使用其他日志记录方法时,可以有一个写入器,也可以有多个读取器,但不能同时具有这两个读取器。

'SQLITE_BUSY‘上的SQLite文档

票数 0
EN

Stack Overflow用户

发布于 2021-03-18 21:09:30

为了检测Sqlite DB是否被锁定,我使用了来自Determine whether SQLite database is locked的方法,这里的想法是尝试获取锁并立即释放它,如果它没有失败,那么DB就没有被锁定。下面的C#代码适用于我:

代码语言:javascript
复制
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;
    }

然后,当您确定数据库是否被锁定时,您可以等待它解锁:

代码语言:javascript
复制
public async Task WaitForDbToBeUnlocked(string dbPath, CancellationToken token)
    {
        while (IsDatabaseLocked(dbPath))
        {
            await Task.Delay(TimeSpan.FromSeconds(1), token);
        }
    }

或者在运行查询之前向其他线程发送取消消息(例如,通过CancellationTokenSource )。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47256792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档