如何用数据读取器执行SQLite查询而不锁定数据库?

我正在使用System.Data.Sqlite访问C#中的SQLite数据库。 我有一个查询必须通过表中的行读取。 在遍历行时以及阅读器打开时,必须执行某些SQL更新。 我遇到了“数据库被锁定”异常。

SQLite文档指出:

当进程想要从数据库文件读取时,它遵循以下步骤顺序:

  • 打开数据库文件并获取SHARED锁。
  • 该文件进一步说明了“共享”锁定:

    数据库可能被读取但不能写入。 任何数量的进程可以同时保存SHARED锁,因此可以有多个同时读取。 但是,当一个或多个SHARED锁处于活动状态时,不允许其他线程或进程写入数据库文件。

    FAQ说:

    多个进程可以同时打开同一个数据库。 多个进程可以同时做一个SELECT。 但是,只有一个过程可以随时对数据库进行更改。

    “SQLite权威指南”指出:

    ...通过使用read_uncommited编译指示,连接可以选择具有读取未提交隔离级别。 如果它设置为true ,那么连接将不会在它读取的表上放置读锁。 因此,另一个写入程序实际上可以更改表,因为处于只读未提交模式下的连接既不能阻止也不能被任何其他连接阻止。

    我试图在SQL查询命令语句中将编译器设置为未提交读取,如下所示:

    PRAGMA read_uncommitted = 1;
    SELECT Column1, Column2 FROM MyTable
    

    使用不同连接的同一线程上的SQL更新仍然失败,并显示“数据库已锁定”异常。 然后我试图将连接实例上的隔离级别设置为未提交读取。 同样的例外情况仍然没有改变。

    我怎样才能完成一个开放的数据读取器循环访问数据库中的行而不锁定数据库,以便我可以执行更新?

    更新:

    这两个答案都在下面。 然而,我已经从使用默认回滚日志到现在使用Write-Ahead Logging,它提供了改进的数据库读取和写入并发性。


    使用WAL模式。


    我无法从这里使用开源数据提供者来工作。 但是,我能够使用dotConnect的免费标准版来工作,如下所示:

    创建下面的DLL导入,以便我们可以为SQLite启用共享缓存。

    [DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int sqlite3_enable_shared_cache(int enable);
    

    执行上述功能启用共享缓存。 请注意,这只需要在整个过程中执行一次 - 请参阅SQLite文档。

    sqlite3_enable_shared_cache(1);
    

    然后将数据阅读器使用的SQL查询语句与pragma语句前缀如下所示:

    PRAGMA read_uncommitted = 1;
    SELECT Column1, Column2 FROM MyTable
    

    现在可以在数据阅读器处于活动状态时自由更新和插入行。 有关共享缓存的其他SQLite文档可以在此处找到。

    更新:

    Devart SQLite数据提供者的新版本现在以改进的方式支持这一点。 要启用共享缓存,可以进行以下调用:

    Devart.Data.SQLite.SQLiteConnection.EnableSharedCache();
    

    例如,可以将未提交的读取配置到连接字符串中,如下所示:

    Devart.Data.SQLite.SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder();
    builder.ReadUncommitted = true;
    builder.DateTimeFormat = Devart.Data.SQLite.SQLiteDateFormats.Ticks;
    builder.DataSource = DatabaseFilePath;
    builder.DefaultCommandTimeout = 300;
    builder.MinPoolSize = 0;
    builder.MaxPoolSize = 100;
    builder.Pooling = true;
    builder.FailIfMissing = false;
    builder.LegacyFileFormat = false;
    builder.JournalMode = JournalMode.Default;
    string connectionString = builder.ToString();
    
    链接地址: http://www.djcxy.com/p/19755.html

    上一篇: How perform SQLite query with a data reader without locking database?

    下一篇: platform and cross