连接时锁定 SQLite 数据库

Lock SQLite database when connecting

我有一个 SQLite 数据库,它保存在网络共享上,可以被多个用户访问。 现在这个数据库的模式需要改变(通过一个自己编写的程序),我需要确保在更新操作期间没有其他用户可以打开数据库(无论是写还是读)。

据我所知,PRAGMA locking_mode=EXCLUSIVE 可用于锁定数据库。不幸的是排他锁只有在执行第一个写操作时才能获得。
这意味着在打开数据库、设置锁定模式和第一次写入操作之间的时间内,不同的用户将能够打开数据库。

有什么方法可以在 打开 数据库时使用 System.Data.SQLite 从 C# 获得独占锁?

编辑 当你请求一些代码时,你去吧:

void UpdateDatabaseSchema(Boolean UpdateNeeded)
{
    // make sure that all SQLite* objects are disposed correctly by using-statement, otherwise database will not be closed correctly!
    using (var Connection = new SQLiteConnection("./Database.db"))
    using (var Command = Connection.CreateCommand())
    {
        Connection.Open();
        Command.CommandText = "PRAGMA locking_mode=EXCLUSIVE;";
        Command.ExecuteNonQuery();
        Command.CommandText = "PRAGMA locking_mode;";
        using (var DataReader = Command.ExecuteReader())
        {
            while (DataReader.Read())
            {
                var Test = DataReader.GetString(0);
            }
        }
        if (UpdateNeeded)
        {
            if (System.Windows.Forms.MessageBox.Show("Do you want to update the database schema?", "Update needed", System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                Command.CommandText = "CREATE TABLE Users (Test TEXT NOT NULL DEFAULT 0);";
                Command.ExecuteNonQuery();
            }
        }
    }
}

显然,锁定模式的读取仅用于调试(并且将被删除以用于生产代码)。
现在,如果另一个用户打开同一个数据库 - 比第一个用户晚一点 - 但点击 "Yes" 更快,会发生什么?第一个用户将收到错误消息,因为架构已更改。
是的,我可以用不同的方式写语句,但这个更新只是一个例子,将来可能 - 并且将会 - 更困难的查询,我不想在每个命令中关心这些竞争条件(至少如果可能的话) .
因此我需要在打开时锁定数据库

@C 帕金斯:
- 在文件系统基础上处理问题是我没有考虑过的事情,我会研究这种可能性,感谢您的意见!
- 在线文档还提到 "The first time the database is written, an exclusive lock is obtained and held." 我知道它仅在连接关闭时释放,问题是它仅在第一次写入操作时 获得

我的测试表明,通过执行任何类型的数据库更改命令,无论它是否实际进行了更改,都可以获得独占锁。换句话说,以下两个命令最终将获得独占锁,但是 WHERE false 使该命令成为空操作。

//* The following only changes the mode, but does not lock the file
Command.CommandText = "PRAGMA locking_mode=EXCLUSIVE;";
Command.ExecuteNonQuery();

try {
    using (var cmdLock = Connection.CreateCommand())
    {
        //* The following command will force an exclusive file lock to be obtained.
        //* Although 'WHERE false' will cause the actual UPDATE to fail,
        //*   the actual statement is valid SQL and will not cause an error. 
        cmdLock .CommandText = "UPDATE Users SET Test = 'bogus' WHERE false;";
        cmdLock .ExecuteNonQuery();
    }
    //* Exclusive lock obtained
    //... free to do updates
} 
catch {
   MessageBox.Show("Failed to obtain exclusive lock, try again later.", "Lock failed")
}