在开发过程中,MongoDB 是一个广泛使用的 NoSQL 数据库。然而,在高并发环境下,会出现写入冲突的问题。本文将介绍 MongoDB 遇到的并发写入冲突,并讨论两种解决方案:乐观锁和悲观锁。
并发写入冲突
在高并发应用程序中,同时对同一文档进行写操作可能会导致写入冲突。例如,两个线程可能同时试图更新相同的文档。这会导致其中一个更新失败,并且需要重新尝试更新。这种情况称为并发写入冲突。
MongoDB 支持多文档事务,但默认情况下,MongoDB 不支持单文档事务。如果多个客户端同时尝试更新相同的文档,则只有一个能够成功更新该文档,其他的将会失败。
乐观锁
乐观锁是基于版本控制的一种机制,在 MongoDB 中通过修改版本字段来实现。给每个文档添加一个版本号字段,类似于 version
或 __v
,然后在更新文档时,比较当前文档版本和原始版本之间的差异,如果它们不匹配,则说明文档已经被另一个客户端更新,当前客户端需要重新尝试更新。
以下是使用乐观锁的示例代码:
-- -------------------- ---- ------- ----- --- - ----- --------------------------------------- ---- --------------- -- ---------- - ---- ------ --- - ----- ---------------------------------------- - ---- -------- ---- ------- -- - ----- - ------- ----------- ---- ------- - - -- ----- - - - - ----- ----- - -- ---------- -
在上面的代码中,我们先读取文档并记录其版本号。然后,我们对该文档进行更改,并在更新期间比较版本号。如果版本号匹配,则会正常更新文档并更新版本号。否则,我们捕获错误并尝试重新更新文档。
悲观锁
悲观锁是一种机制,在必须完成写操作之前阻止其他客户端访问被锁定的文档。MongoDB 中的悲观锁可以通过使用 findAndModify
或 update
命令中的 { $isolated: 1 }
标志来实现。
以下是使用悲观锁的示例代码:
await db.command({ findAndModify: "myCollection", query: { _id: ObjectId("..."), field5: 123 }, update: { ... }, new: true, fields: { field1: 1, _id: 0 }, isolated: 1 // 使用悲观锁 })
在上面的代码中,我们使用 findAndModify
命令并设置 isolated: 1
标志来启用悲观锁。这会阻止其他客户端对该文档进行写操作。
结论
乐观锁和悲观锁都可以解决 MongoDB 的并发写入冲突问题。具体选择哪种锁取决于应用程序的要求和场景。如果需要最大限度地减少锁定时间,则应使用乐观锁。而如果需要优先保证数据一致性,则应该使用悲观锁。
除此之外,为了避免更新失败重试带来的额外开销,还可以采用其他
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6754b7a41b963fe9cc50024c