SQLite与.NET 6中无法读取未提交数据问题求助
SQLite .NET 6 脏读失败问题解决
核心问题原因
你的代码配置了共享缓存和read_uncommitted,但依然无法脏读,核心原因是SQLite默认的DELETE日志模式会在写入事务期间锁定整个数据库,其他连接即便开启脏读也无法访问未提交数据。只有切换到WAL(Write-Ahead Log)日志模式,才能实现并发读写,让脏读生效。
修正步骤
1. 切换到WAL日志模式
在首次连接数据库时执行一次日志模式切换(只需执行一次,后续连接会自动沿用该设置):
using var initConn = new SQLiteConnection(Constants.connectionString); initConn.Open(); using var initCmd = new SQLiteCommand("pragma journal_mode=WAL;", initConn); initCmd.ExecuteScalar(); initConn.Close();
2. 调整连接与事务配置
- 确保两个连接都启用
cache=shared - 在连接字符串中直接指定
Read Uncommitted=True,避免手动执行pragma的时机问题 - 写入事务保持未提交状态
修正后的完整代码:
// 初始化WAL模式(仅需执行一次) using var initConn = new SQLiteConnection(Constants.connectionString); initConn.Open(); using var initCmd = new SQLiteCommand("pragma journal_mode=WAL;", initConn); initCmd.ExecuteScalar(); initConn.Close(); // 第一个连接:开启事务插入数据 using var connection1 = new SQLiteConnection($"{Constants.connectionString};cache=shared;Read Uncommitted=True"); connection1.Open(); using var transaction1 = connection1.BeginTransaction(); for (int i = 0; i < Constants.iterations; i++) { using var cmd = new SQLiteCommand($"insert into {Constants.tableName} (Description) values ('test')", connection1); cmd.ExecuteNonQuery(); // 插入操作使用ExecuteNonQuery更合理 } // 第二个连接:读取未提交数据 using var connection2 = new SQLiteConnection($"{Constants.connectionString};cache=shared;Read Uncommitted=True"); connection2.Open(); using var cmd2 = new SQLiteCommand($"select count(*) from {Constants.tableName}", connection2); var count = cmd2.ExecuteScalar(); Console.WriteLine($"未提交数据读取结果:{count}"); // 此时会返回插入的行数,实现脏读 // 根据需求选择提交或回滚事务 // transaction1.Commit(); // transaction1.Rollback();
关键注意事项
- WAL模式是脏读生效的前提:DELETE日志模式下写操作会独占数据库锁,无法实现并发读写;WAL模式允许读连接在写事务未提交时访问数据库快照。
- 连接字符串参数规范:System.Data.SQLite中需用
Read Uncommitted=True作为连接字符串参数,而非手动执行pragma read_uncommitted=true,这样能确保在连接初始化时就正确设置脏读权限。 - 共享缓存必须一致:两个连接都必须指定
cache=shared,否则无法共享未提交的数据缓存。
内容的提问来源于stack exchange,提问作者Thaiger
相关产品推荐
相关产品推荐

