了解firebase中的冲突解决方案

Nav*_*een 5 firebase firebase-realtime-database

我正在尝试理解冲突解决方案在firebase中的工作方式,我需要一些帮助.

假设我将json对象保存在firebase实时的节点中:

{
    "shape": "rectangle",
    "stroke": 10, 
    "color": "black"
}
Run Code Online (Sandbox Code Playgroud)

我已经定义了一个测试页面,它可以读取这些数据并进行显示,并且还可以实时监听节点上发生的变化.我添加了一个更新数据的条款,最终只更新特定的键值.

用例示例

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"}
Run Code Online (Sandbox Code Playgroud)

理想情况下,由于客户端1在稍后的时间点进行了比客户端2更改,因此当客户端2数据被同步时,应该保留客户端1的改变.

如果有人可以建议我在firebase中解决这种类型的冲突(可能是通过定义一些规则和一些额外的逻辑),我会很高兴.

Fra*_*len 9

使用当前代码,预期的行为确实是最后一次写入获胜.

还有两个选择:

  1. 使用事务检测数据是否已更改,然后重试.
  2. 通过使用将写入与每个客户端分开的数据结构,完全防止冲突.

让我们依次看看每一个.

使用事务是解决此问题的最常见方法.在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 */
Run Code Online (Sandbox Code Playgroud)

在这种数据结构中,没有人覆盖其他人的数据(在安全规则中易于实施的东西).每个人只是在形状上添加新的更新(使用ref.push(),按时间顺序生成唯一的位置).

要获取形状的当前数据,每个客户端都需要读取该形状的所有更新并在客户端上重新计算它们.对于大多数用例,我看到这是一个简单的操作,但如果没有:使用Cloud Function计算状态的周期性快照非常容易.

  • 您可以做的一件事是在每次更新中都有一个客户端时间戳.然后,您的安全规则可以通过将时间戳与"now"进行比较来拒绝它认为已过期的更新. (2认同)