我正在尝试了解冲突解决方案在我需要一些帮助的火中的工作方式。
假设我已经在firebase中保存了json对象实时:
{
"shape": "rectangle",
"stroke": 10,
"color": "black"
}
我已经定义了一个测试页面,该页面读取此数据并显示,并听取实时使用键在节点上发生的更改。我添加了一个规定来更新数据,该数据最终仅更新特定的键值。
样品二手情况
client 1 - loads the page
data - {"shape": "rectangle", "stroke": 10, "color": "black"}
client 2 - loads the page
data - {"shape": "rectangle", "stroke": 10, "color": "black"}
client 2 goes offline
client 2 updates stroke value to 20
data - {"shape": "rectangle", "stroke": 20, "color": "black"}
* data is yet to sync to the server
client 1 makes a change after client 2 has already done with its changes and changes stroke to 5
data - {"shape": "rectangle", "stroke": 5, "color": "black"}
* data gets synced to the server immediately
client 2 comes online and pushes its changes and overrides the changes made by client 1
data - {"shape": "rectangle", "stroke": 20, "color": "black"}
理想情况下,由于客户端1在以后的时间点进行更改,而不是客户端2当客户2数据同步时客户端1的更改应保留。
我会很高兴,如果有人可以建议我在firebase中解决这种冲突的方法(可能是定义一些规则和一些额外的逻辑(。
使用您的当前代码,预期的行为确实是最后一篇文字获胜。
还有其他两个选项:
- 使用交易检测数据已经更改,然后重试。
- 通过使用将写入与每个客户分开的数据结构,完全防止冲突。
让我们依次看看每个。
使用交易是围绕此问题的最常见方法。当您在Firebase中使用交易时,客户端将向服务器发送"比较并设置"操作。这是类型的指令:"如果当前值为a,则将其设置为b"。在您的情况下,这意味着第二个写入检测中风已经改变了,因此会重试。
要了解有关交易的更多信息,请查看Firebase文档,并在我在这里回答有关它们的工作方式。
这听起来像是一个很好的解决方案,但不幸的是,它确实会影响代码的可扩展性。用户试图修改相同数据的用户越多,交易必须重试的可能性就越大。这就是为什么要完全避免冲突总是很好的原因。
防止冲突是目前最好的冲突解决策略。通过防止冲突,您永远不必解决这些冲突,这意味着您不必编写代码来解决冲突,这意味着您的应用程序将扩展得更好/更远。
为了防止冲突,您需要寻找一个数据结构,您的用户始终将其写入唯一位置。在您的用例中,您可以让客户端将其"更新操作"写入更新的队列,而不是让每个客户端更新中风。例如:
shapes
shapeid1
pushid1: {"shape": "rectangle", "stroke": 10, "color": "black"} /* initial data */
pushid2: { "stroke": 5 } /* first update */
pushid3: { "stroke": 20 } /* second update */
在此数据结构中,没有人覆盖其他任何人的数据(在安全规则中易于执行(。每个人都只是将新更新附加到形状上(使用ref.push()
,以按时间顺序生成唯一的位置(。
要获取形状的当前数据,每个客户端将需要读取该形状的所有更新并在客户端上重新计算它们。对于我所看到的大多数用例,这是一个简单的操作,但如果不是这样:具有云功能非常容易计算状态的定期快照。