首页 > 解决方案 > Firestore 事务锁会阻止读取吗?(服务器端SDK)

问题描述

我有一个带有 @google-cloud/firestore 的 Node.js 应用程序,它有两个集合 A 和 B。

Collection A 文档有一个名为“name”的字段和一个名为“collectionBId”的字段。集合 B 文档只有一个名为“名称”的字段。集合 A 和 B 中的名称是唯一的。

// Collection A
{ id: 1, name: 'example1', nameB: 'example2' }

// Collection B
{ id: 1, name: 'example2' }

Node.js 中有一个端点可以:

const result = await firestore.runTransaction(async transaction => {
    const refA = firestore.collection('A').where('name', '==', reqParam1)
    const {docs: docsA} = await transaction.get(refA)
    const refB = firestore.collection('B').where('name', '==', docsA[0].data().name).where('name', '==', reqParam2)
    const {docs: docsB} = await transaction.get(refB)
    return docsB[0].data()
})

这比(少一个往返)要快得多:

const {docs: docsA} = await firestore.collection('A').where('name', '==', reqParam1).get()
const {docs: docsB} = await firestore.collection('B').where('name', '==', docsA[0].data().name).where('name', '==', reqParam2).get()
const result = docsB[0].data()

事务在 Node.js 中以悲观锁运行,但不清楚多个用户是否可以同时使用此事务(例如 100 个用户)。

在文档中,提到当执行写入时,有一个锁可以防止并发写入,是否也会阻止读取?此外,如果大量使用读取事务,会阻止写入吗?

这导致以下两个问题:

  1. Firestore 读取事务是否会阻止 Node.js 中的其他读取事务?
  2. Firestore 读取事务会阻止 Node.js 中的写入事务吗?

标签: node.jsfirebasegoogle-cloud-firestoretransactions

解决方案


(最终?)编辑 4: github问题被标记为已修复,文档将被更新,所以现在我们知道事务是如何工作的

您可以使用传递给的事务对象updateFunction来读取和修改处于锁定状态的 Firestore 文档。在执行任何写入之前,您必须执行所有读取。

在事务期间读取的文档被悲观地锁定。文档上的事务锁会阻止其他事务、批量写入和其他非事务性写入更改该文档。事务在提交时或在超时或因任何原因失败时释放其文档锁。

一旦updateFunction解决,事务就会提交。如果事务因争用而失败,则事务最多重试五次。updateFunction每次尝试调用一次。

如果没有读取任何文档,事务会在 60 秒后超时。在 270 秒内未提交的事务也将被中止。

编辑 3a:我从Github存储库 中找到了有关交易的更多“官方”信息:

如果您通过服务器 SDK 使用 runTransaction() API 读取文档,则后端将阻止其他客户端修改文档,直到事务提交。此锁定最多可保持 270 秒。我们在文档中将此称为“悲观锁定”,并且所有 Firestore Server SDK 都公开了这些语义。

在极少数情况下,后端会中止当前正在运行的事务(例如,如果争用过多),在这种情况下,所有 SDK 都会重试,而与获取锁的方式无关。

如果你有两个正在运行的事务都试图读取同一个文档,第一个将成功,第二个将挂起,直到第一个完成。

还提出了一个 github问题,要求改进有关交易的文档。

编辑 2:对于服务器端 SDK,我发现了一个可能有帮助的响应,但是没有关于事务如何工作的官方文档,除了它运行悲观锁,理论上允许所有读取,除非它尝试写入,在这种情况下它将放置一个独占锁定记录以防止其他用户对其进行操作

编辑:下一个响应仅适用于运行乐观锁的客户端 SDK,不适用于运行悲观锁的服务器端 SDK

  1. 不,读取事务不会阻止另一个读取事务。
  2. 不,读取事务不会阻止写入事务。

事实上,您必须注意,如果在执行事务时更改了读取的内容,则读取事务可能会运行多次,这样做是为了确保内容是最新的。

可以在此处找到有关此行为的更多信息

如果一个事务读取文档并且另一个客户端修改了任何这些文档,Cloud Firestore 会重试该事务。此功能可确保事务在最新且一致的数据上运行。

和这里

(使用事务时,请注意)如果并发编辑影响事务读取的文档,则调用事务(事务函数)的函数可能会运行多次。


推荐阅读