交易可以在收款时使用吗?
Posted
技术标签:
【中文标题】交易可以在收款时使用吗?【英文标题】:Can transaction be used on collection? 【发布时间】:2019-07-18 00:04:52 【问题描述】:我正在使用 Firestore,并尝试通过使用事务删除 Flutter 应用中的竞争条件。
我有最多添加 2 个文档的子集合。
竞争条件意味着可能会添加 2 个以上的文档,因为客户端代码使用 setData
。例如:
Firestore.instance.collection(‘collection').document('document').collection('subCollection’).document(subCollectionDocument2).setData(
‘document2’: documentName,
);
我正在尝试使用事务来确保最多添加 2 个文档。因此,如果在事务运行时集合发生了变化(例如新文档添加到集合中),事务将失败。
但我读过文档,似乎事务更多地用于在文档中设置字段的竞争条件,而不是在子集合中添加文档。
例如,如果尝试实现:
Firestore.instance.collection(‘collection').document('document').collection('subCollection').runTransaction((transaction) async
),
给出错误:
错误:没有为类“CollectionReference”定义方法“runTransaction”。
事务可以用于监控子集合的变化吗?
有人知道其他解决方案吗?
【问题讨论】:
【参考方案1】:事务可以用于监控子集合的变化吗?
Firestore 中的事务由所谓的compare-and-swap operation 工作。在事务中,您从数据库中读取文档,确定其当前状态,然后根据该状态设置其新状态。当您为整个事务完成此操作后,您将整个当前状态和新状态文档包发送到服务器。然后,服务器检查存储层中的当前状态是否仍然与您的客户端开始时的状态相匹配,如果是,则提交您指定的新状态。
知道了这一点,在事务中监控整个集合的唯一方法就是将该集合中的所有文档读入事务中。虽然这对于小型集合在技术上是可行的,但它的效率可能非常低,而且我从未见过在实践中这样做过。再说一次,对于您集合中的两个文档,在事务中简单地读取它们可能是完全可行的。
请记住,虽然事务仅确保数据一致,但不一定限制恶意用户可以执行的操作。如果要确保集合中的文档不超过两个,则应查看服务器端机制。
最简单的机制(基础设施方面)是使用 Firestore 的服务器端安全规则,但我认为这些规则不会限制集合中的文档数量,正如 Doug 在他对Limit a number of documents in a subcollection in firestore rules 的回答中所解释的那样。
在这种情况下,最可能的解决方案是(正如 Doug 所建议的)使用 Cloud Functions 将文档写入子集合中。这样您就可以简单地拒绝来自客户端的直接写入,并在您的 Cloud Functions 代码中强制执行您想要的任何业务逻辑,这些代码在受信任的环境中运行。
【讨论】:
感谢您的回复!但我看不到 Cloud Functions 如何停止竞争条件。正如 Doug 解释的那样,它们不能同步工作 正确。但是它们在受信任的环境中运行,因此您可以编写代码以确保遵循您的业务规则。例如:1)加载集合中的所有文档,2)计算它们,3a)如果多于 2 个,则返回错误,3b)如果少于 2 个,则写入来自用户的文档。 谢谢。我现在正在尝试测试这个。但从理论上讲,我仍然认为可能会收集超过 2 个文档的结果。因为如果 2 个函数实例同时运行并计算集合中的文档并且只看到 1 个文档。然后他们都将写入集合。所以问题是收集中的计数文档(步骤 2)和写入(步骤 3)之间的时间差。我说的对吗? 这就是事务的来源。你仍然会在服务器端代码中使用事务,你只是保证这是编写这些文档的唯一方法。 谢谢!但是你说监控整个集合非常低效?以上是关于交易可以在收款时使用吗?的主要内容,如果未能解决你的问题,请参考以下文章