MongoDB,网上没有关于事务和读取操作交互的信息

MongoDB, there is no info online about transactions and read operations interaction

我正在尝试了解全貌... 当我创建一个会话时,我知道与该会话关联的所有写操作将一起成功或一起回滚。

我没有找到任何官方 mongo 文档来解释什么事务锁定以及在事务生命周期中锁定何时发生(我所说的锁定指的是悲观锁或乐观锁)

post here seems 基于这样的假设,即在会话结束时文档被更新和释放后文档开始锁定。

但是文档甚至需要锁定吗?它真的在那一瞬间锁定了吗?我在哪里可以找到相关文档?

这意味着如果我这样做

const person = await findOne({ id },{ session })
const updatedPerson = await updateOne({ id },{ person },{ session , new: true})

sessionfindOne上完全没有意义?因为特定的 person 文档没有被锁定?

因此,如果在我找到此人和更新此人之间,其他一些请求已更新 PersonupdatedPerson 实际上可能与 person 不同,对吗?没有 mongoDB 以会话方式内置以确保 person 将被锁定? (我知道 optimisticConcurrency 有一个模式选项,但我想了解会话,而且这个选项似乎仅限于抛出错误而不是重试,考虑到通常你想要的行为,这似乎有点奇怪optimisticConcurrency 是重试或者至少可以选择)

如果这是正确的,那么 session 严格执行 read 操作的唯一原因是能够查看作为会话一部分的 write 结果。

const updatedPerson = await updateOne({ id },{ field1: 'changed' },{ session , new: true})
const person = await findOne({ id} ,{ session })

在这里将 personsession 相关联让我可以查看 updatedPerson post 更新。

我的理解正确吗?如果是这样,那就引出了下一个问题,特别是关于 mongoose with .save()。根据mongoose documentation

For example, if you're using save() to update a document, the document can change in MongoDB in between when you load the document using findOne() and when you save the document using save() as show below. For many use cases, the save() race condition is a non-issue. But you can work around it with findOneAndUpdate() (or transactions) if you need to.

这提出了我的问题,考虑到事务不锁定读取的文档,您如何解决 save() 事务竞争条件?

我使用 await new Promise((r) => setTimeout(r, 5000)); 进行了一些手动测试,并在会话正在进行时更新文档以观察其行为。

我的发现如下:

在这个例子中:

const person = await findOne({ id },{ session })
const updatedPerson = await updateOne({ id },{ $set: { ...person } },{ session , new: true})

对于 findOne 上的 session 的意思,即使 findOne 操作没有锁定文档,它也会导致updateOne 失败并中止事务 if findOne 获取的文档,在我们的例子中 person,被不属于交易的一部分。

这意味着您可以相信 updatedPerson 将是 person,因为 person 是会话的一部分。这个答案使我的其余问题变得无关紧要。