使用Lightning.NET操作LMDB时并发读写触发BadCommand错误
问题解决:Lightning.NET+LMDB并发读写命名数据库触发BadCommand错误
问题原因
你遇到的BadCommand错误本质是LMDB的数据库元数据锁冲突:
- 当写事务中使用
DatabaseOpenFlags.Create打开命名数据库时(哪怕数据库已经存在),LMDB会尝试修改全局的数据库元数据并持有锁; - 此时并行的读事务尝试打开同一个命名数据库,需要读取元数据,但被写事务的锁阻塞,最终返回
BadCommand错误; - 无名称的默认数据库不会触发这个问题,因为它的元数据不会被常规读写操作修改。
解决方案
核心是避免在写事务中重复执行数据库创建操作,提前初始化所有需要的命名数据库,后续读写事务仅打开已存在的数据库:
1. 提前初始化命名数据库
在程序启动、开始并发操作前,用单独的事务一次性创建所有需要的命名数据库:
using var environment = new LightningEnvironment("test") { MaxDatabases = 1 }; environment.Open(); // 全局初始化:仅执行一次,创建需要的命名数据库 using (var initTx = environment.BeginTransaction()) { initTx.OpenDatabase( name: "db1", configuration: new DatabaseConfiguration { Flags = DatabaseOpenFlags.Create } ); initTx.Commit(); }
2. 修改读写事务的数据库打开逻辑
- 写事务:去掉
DatabaseOpenFlags.Create,仅打开已存在的数据库:
// WriteTask中的OpenDatabase代码 using var db = tx.OpenDatabase(name: "db1");
- 读事务:保持原有逻辑不变即可,因为它本来就只是打开已存在的数据库。
3. 验证环境配置
确保LightningEnvironment的MaxDatabases值大于等于你实际使用的命名数据库数量,避免超出限制。
修改后的效果
调整后,并发读写操作不会再触发BadCommand,因为写事务不再修改数据库元数据,读写事务的锁只会作用于各自操作的数据范围,无关数据的并发操作完全隔离。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

