使用TransactionScope操作内存优化表时遇SNAPSHOT隔离级别错误
问题本质
内存优化表的隔离级别逻辑和传统磁盘表完全不同:即使你开启了所有快照相关参数,也不能显式把事务/会话的隔离级别设为SNAPSHOT。SQL Server对内存优化表的快照隔离支持,是通过自动提升机制实现的,而非直接指定SNAPSHOT级别。
你开启的is_memory_optimized_elevate_to_snapshot_on=1参数,就是用来把针对内存优化表的READ COMMITTED请求,自动升级为SNAPSHOT隔离级别——这才是内存优化表实现无锁读写的正确路径。
解决步骤
调整TransactionScope的隔离级别
删掉代码中显式指定IsolationLevel.Snapshot的部分,改用默认的ReadCommitted(或者不指定隔离级别,默认就是这个)。示例代码:using (var scope = new TransactionScope()) // 默认就是ReadCommitted,无需额外指定 { // 执行内存优化表的写入操作 // ... scope.Complete(); } // 或者显式指定ReadCommitted(效果一致) using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) { // 写入逻辑 scope.Complete(); }这样配置后,针对内存优化表的操作会自动触发隔离级别提升,既解决了你遇到的
READ COMMITTED间歇性锁问题,又不会触发报错。验证数据库参数配置
执行以下SQL确认参数是否正确生效:SELECT name AS 数据库名, snapshot_isolation_state, is_read_committed_snapshot_on, is_memory_optimized_elevate_to_snapshot_on, is_memory_optimized_enabled FROM sys.databases WHERE name = '你的数据库名称';确保所有四个参数的值都是
1,尤其是is_memory_optimized_elevate_to_snapshot_on必须为1,自动提升机制才会正常工作。
补充说明
内存优化表支持的显式隔离级别只有REPEATABLE READ、SERIALIZABLE,以及针对只读操作的SNAPSHOT(写入操作不支持显式SNAPSHOT)。所以不要尝试显式设置SNAPSHOT级别,依赖自动提升是最稳妥的方案,既能实现无锁的快照隔离效果,又符合SQL Server对内存优化表的约束。
内容的提问来源于stack exchange,提问作者Sean McKinney

