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})
session
在findOne
上完全没有意义?因为特定的 person
文档没有被锁定?
因此,如果在我找到此人和更新此人之间,其他一些请求已更新 Person
,updatedPerson
实际上可能与 person
不同,对吗?没有 mongoDB 以会话方式内置以确保 person
将被锁定? (我知道 optimisticConcurrency
有一个模式选项,但我想了解会话,而且这个选项似乎仅限于抛出错误而不是重试,考虑到通常你想要的行为,这似乎有点奇怪optimisticConcurrency 是重试或者至少可以选择)
如果这是正确的,那么 session
严格执行 read
操作的唯一原因是能够查看作为会话一部分的 write
结果。
const updatedPerson = await updateOne({ id },{ field1: 'changed' },{ session , new: true})
const person = await findOne({ id} ,{ session })
在这里将 person
与 session
相关联让我可以查看 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
是会话的一部分。这个答案使我的其余问题变得无关紧要。
我正在尝试了解全貌... 当我创建一个会话时,我知道与该会话关联的所有写操作将一起成功或一起回滚。
我没有找到任何官方 mongo 文档来解释什么事务锁定以及在事务生命周期中锁定何时发生(我所说的锁定指的是悲观锁或乐观锁)
post here seems 基于这样的假设,即在会话结束时文档被更新和释放后文档开始锁定。
但是文档甚至需要锁定吗?它真的在那一瞬间锁定了吗?我在哪里可以找到相关文档?
这意味着如果我这样做
const person = await findOne({ id },{ session })
const updatedPerson = await updateOne({ id },{ person },{ session , new: true})
session
在findOne
上完全没有意义?因为特定的 person
文档没有被锁定?
因此,如果在我找到此人和更新此人之间,其他一些请求已更新 Person
,updatedPerson
实际上可能与 person
不同,对吗?没有 mongoDB 以会话方式内置以确保 person
将被锁定? (我知道 optimisticConcurrency
有一个模式选项,但我想了解会话,而且这个选项似乎仅限于抛出错误而不是重试,考虑到通常你想要的行为,这似乎有点奇怪optimisticConcurrency 是重试或者至少可以选择)
如果这是正确的,那么 session
严格执行 read
操作的唯一原因是能够查看作为会话一部分的 write
结果。
const updatedPerson = await updateOne({ id },{ field1: 'changed' },{ session , new: true})
const person = await findOne({ id} ,{ session })
在这里将 person
与 session
相关联让我可以查看 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
是会话的一部分。这个答案使我的其余问题变得无关紧要。