锁不会自动释放,仅在aborttransaction()、committransaction()成功或事务超时被强制中止时才释放;事务失败抛异常不等于锁释放,漏调aborttransaction()会导致锁持续持有。

不会自动释放,但会按事务边界释放——abortTransaction() 或超时中止后,锁才真正解除。
事务失败时锁不立刻消失
MongoDB 的文档级锁由 WiredTiger 引擎管理,锁的生命周期严格绑定事务状态。事务失败(比如抛出 WriteConflict)本身只是异常信号,不等于锁已释放;只有显式调用 abortTransaction()、或事务被后台清理机制强制中止后,锁才会释放。
- 常见错误:只捕获异常却漏掉
session.abortTransaction(),导致锁持续持有,后续写请求卡在waitingForLock: true - 更隐蔽的情况:事务里混了 HTTP 调用,超时前没走到
abort,session 仍处于 open 状态,锁就一直挂着 - 注意:驱动 ≥ 4.3 的
ClientSession.close()不等于abortTransaction(),它只释放网络连接,事务和锁依然存在
哪些情况会触发锁释放?
锁释放只发生在以下明确的事务终结点:
-
session.abortTransaction()执行成功(幂等,可重复调用) -
session.commitTransaction()成功完成(此时锁随提交一并释放) - 事务超时被强制中止:默认
maxTransactionTimeMS=60000(60 秒),从事务首次操作起计时,超时后 mongod 主动中止并释放锁 - 客户端连接断开且 session 未 close:WiredTiger 会在连接关闭后清理 session,但有延迟窗口,不是瞬时行为
如何确认锁是否已释放?
别靠猜,直接查活跃操作:
- 运行
db.currentOp({ "waitingForLock": true }),看是否还有同lsid的阻塞项 - 检查
db.serverStatus().lock.currentQueue.writers是否回落 - 若发现某事务
secs_running很大但waitingForLock为 false,说明它正持锁执行中,不是已失败——失败事务不会“正在运行”,只会 pending 或已中止
最容易被忽略的释放时机
事务内写操作(如 updateOne)获取文档锁是逐条进行的,不是“整个事务一把锁”。所以部分操作成功、部分失败时,前面已加锁的文档仍被锁定,直到 abort 或超时触发全局清理。这意味着:一个 5 步更新的事务,第 3 步失败后,前 2 步改过的文档锁还在,必须靠 abortTransaction() 显式收尾,否则它们会卡住其他写请求至少几十毫秒甚至更久。











