用于复杂写入的 Firebase 提交/回滚

2023-11-23

我正在使用 Firebase 编写一个金融应用程序,为了提交收据,还需要更新许多其他对象。为了使数据有效,所有数据更新都需要成功完成。如果其中一项写入出现错误,则必须回滚所有更新。

例如:

如果用户提交收据,则必须更新收据对象以及发票对象以及其他总账对象。

如果更新开始但用户中途失去了互联网连接,则应回滚所有更改。

在 Firebase 中实现此目标的最佳方法是什么?


首先,让我们讨论一下为什么有人可能想要在多个数据路径上进行提交/回滚......

你需要这个吗?

一般来说,如果出现以下情况,则不需要此选项:

  • 您没有以高并发性进行写入(不同用户每分钟对同一记录进行数百次写入操作)
  • 您的依赖关系很简单(B 依赖于 A,C 依赖于 A,但 A 不依赖于 B 或 C)
  • 您的数据可以合并到单个路径中

开发人员有点过于担心数据中出现孤立记录。 Web 套接字在一次写入和另一次写入之间失败的可能性可能微不足道,并且与之间的冲突顺序类似。 基于时间戳的 ID。这并不是说这是不可能的,但它通常后果很低,可能性很小,不应该是您的主要关注点。

此外,使用脚本甚至只需在 JS 控制台中输入几行代码即可非常轻松地清理孤儿。再说一次, 它们的后果往往非常低。

除了这个你还能做什么呢?

将必须以原子方式写入的所有数据放入单个路径中。然后你可以把它写成一个单一的set or a 交易如果需要的话。

或者,如果一条记录是主记录,而其他记录依赖于此,则只需先写入主记录,然后在回调中写入其他记录即可。添加安全规则来强制执行此操作,以便主记录始终存在,然后才允许其他记录写入。

如果您只是为了轻松快速地迭代数据而对数据进行非规范化(例如,获取用户名称列表),那么只需在单独的路径中索引该数据即可。 然后,您可以将完整的数据记录放在单个路径中,并将姓名、电子邮件等放在快速、查询/排序友好的列表中。

这什么时候有用?

如果您有一组非规范化记录,则这是一个合适的工具:

  • 无法以实际的方式合并到一条路径中
  • 具有复杂的依赖关系(A 依赖于 C,C 依赖于 B,B 依赖于 A)
  • 记录以高并发性写入(即不同用户每分钟可能对同一记录进行数百次写入操作)

你怎么做到这一点?

这个想法是使用更新计数器来确保所有路径保持相同的修订版本。

1) 创建一个更新计数器,该计数器使用事务递增:

function updateCounter(counterRef, next) {
   counterRef.transaction(function(current_value) {
      return (current_value||0)+1;
   }, function(err, committed, ss) {
      if( err ) console.error(err)
      else if( committed ) next(ss.val());
   }, false);
}

2)给它一些安全规则

"counters": {
   "$counter": {
      ".read": true,
      ".write": "newData.isNumber() && ( (!data.exists() && newData.val() === 1) || newData.val() === data.val() + 1 )"
   }
},

3) 为您的记录提供安全规则以强制执行 update_counter

"$atomic_path": {
   ".read": true,
   // .validate allows these records to be deleted, use .write to prevent deletions
   ".validate": "newData.hasChildren(['update_counter', 'update_key']) && root.child('counters/'+newData.child('update_key').val()).val() === newData.child('update_counter').val()",
   "update_counter": {
      ".validate": "newData.isNumber()"
   },
   "update_key": {
      ".validate": "newData.isString()"
   }
}

4)用update_counter写入数据

由于您已制定安全规则,因此只有在计数器不移动的情况下才能成功写入记录。如果它确实移动,那么记录已被并发更改覆盖,因此它们不再重要(它们不再是最新和最好的)。

var fb = new Firebase(URL);

updateCounter(function(newCounter) {
   var data = { foo: 'bar', update_counter: newCounter, update_key: 'myKey' };
   fb.child('pathA').set(data);
   fb.child('pathB').set(/* some other data */);
   // depending on your use case, you may want transactions here
   // to check data state before write, but they aren't strictly necessary
});

5)回滚

回滚涉及更多一些,但可以根据以下原则构建:

  • 在调用 set 之前存储旧值
  • 监控每个设置操作是否失败
  • 对任何已提交的更改设置回旧值,但保留新计数器

预建库

我今天写了一个库来执行此操作塞到了 GitHub 上。请随意使用它,但请确保阅读“您需要这个吗?”不会让您的生活变得复杂。多于。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用于复杂写入的 Firebase 提交/回滚 的相关文章

  • 从 Firebase 数据库填充微调器

    public class MainActivity extends AppCompatActivity DatabaseReference reference Spinner areaSpinner ArrayList
  • iOS 10 的错误? NSDate 日本地区时间描述和 24 小时休息

    这似乎是 iOS 10 的一个错误 在 iOS 8 和 9 中都可以 NSDate date description 的小时描述是错误的 它附加了 24 小时描述和 12 小时描述 我没有使用 NSDateFormatter 只是默认设置
  • 如何读取firebase推送通知内容并在ionic2中触发方法?

    是否可以访问push notificationionic 2 中的内容并在通知到达时执行一堆代码或event fire 我建议使用科尔多瓦插件 firebase https github com arnesson cordova plugi
  • 如何在 Apple Watch Extension/App 和 iOS App 之间建立通信通道

    我正在探索 WatchKit SDK 当我有 WatchKit 应用程序时 是否可以在 WatchKit 应用程序上从 iPhone 应用程序设置值 例如文本 设置 我可以从 iPhone 应用程序调用 WatchKit 应用程序扩展中的函
  • 暂停视频录制[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在尝试创建一个应用程序 用户可以在其中从相机录制视频 该应用程序的功能之一必须是文件录制中的暂停 例如 用户通过按 开始 按钮开始
  • iOS 11 安全区域布局指南向后兼容性

    启用安全区域布局指南是否与 iOS 11 以下版本兼容 我设法使用新的安全区域布局指南并保持与 iOS 9 和 iOS 10 的向后兼容性 编辑 正如 NickEntin 的评论所指出的 此实现将假定存在状态栏 但在 iPhone X 的横
  • iOS中的performSelector有什么用

    的作用是什么执行选择器 比较 self btnClicked and self performSelector selector btnClicked void btnClicked NSLog Method Called 两者都对我来说工
  • UICollectionView 未出现

    我正在尝试设置UICollectionView 以编程方式在我的视图控制器中扩展UIViewController 由于某种原因 我的收藏视图根本没有显示 以下是我所拥有的 为什么没有出现 我将它连接到委托和数据源并将其添加为子视图self
  • iOS UIButton 带有圆角和背景 bug

    我发现圆形 UIButton 存在一个奇怪的问题 这是我创建此按钮的代码块 let roundedButton UIButton type System roundedButton frame CGRectMake 100 100 100
  • Firebase 数据库快速入门处理计数的方式安全吗?

    我想为文章点赞创建一个增量字段 我指的是这个链接 https firebase google com docs database android save data save data as transactions https fireb
  • 如何使用 Swift 获取 YouTube 频道的所有播放列表?

    我的问题不是关于从一般频道检索视频 我只想获取该频道创建的所有 播放列表 并检索每个播放列表的缩略图 标题和视频数量 这是一个 YouTube 频道示例 正如您所看到的 有很多已创建的播放列表 截至目前 我只能获取某个频道最新上传的视频 在
  • 线程 1:信号 SIGABRT - AppDelegate.h

    main m Journey Created by Julian Buscema on 2014 07 13 Copyright c 2014 Julian Buscema All rights reserved import
  • FireMonkey iOS RAD Studio XE2 - 在从 URL 加载的表单上显示图像

    是否可以将 TImage 放置在 iOS 的 FMX 表单上 并将图像 jpg 从 URL 加载到此 TImage 中以在 iOS 应用程序中显示 我尝试过但没有成功 任何正确方向的提示或指出都会受到赞赏 将 TButton TImageC
  • iPhone 快照,包括键盘

    我正在寻找拍摄整个 iPhone 屏幕 包括键盘 的正确方法 我找到了一些截取屏幕的代码 CGRect screenCaptureRect UIScreen mainScreen bounds UIView viewWhereYouWant
  • 检查 touchend 是否在拖动后出现

    我有一些代码可以更改表的类 在手机上 有时表格对于屏幕来说太宽 用户将拖动 滚动来查看内容 但是 当他们触摸并拖动表格时 每次拖动都会触发 touchend 如何测试触摸端是否是触摸拖动的结果 我尝试跟踪dragstart和dragend
  • 对使用phonegap和钛的质疑[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 最近我听说了 PhoneGap 和 Titanium 移动网络应用程序的开发 我分析了这两个 Web 应用程序 并了解了如何使用它们以
  • 如何更改已上传的 Firebase 存储图像文件名?

    我需要更改已上传到 firebase 存储中的文件名 因为 在 firebase 存储中上传图像后 我将 url 保存在 firebase 数据库中的特定子 文件夹 下 但是 当我将图像移动到另一个子 文件夹 时 我需要根据新名称更改存储中
  • Swift 中通过不同类调用委托方法

    我正在获取 JSON 菜单 一旦 JSON 返回 我想运行 menuReady 来更新表的内容在 SomeTableViewController 类中 但下面的代码似乎不起作用 AIM Run 菜单就绪 JSON 返回后更新内容 PROBL
  • 退出导航控制器

    我试图离开初始视图控制器 并进入空白视图控制器 这很好 但是这会使空白视图控制器也成为导航控制器的一部分 这不是我想要的 我想脱离视图控制器 在视图控制器中 我尝试退出 它会自行弹出 当我尝试视图中的方法时 将出现目标视图控制器 self
  • 显示键盘时如何在 TextView 下方添加更多填充

    当我在 ScrollView 中有 TextField 并点击它时 键盘会按预期显示 但似乎 TextField 已向上移动到足以显示输入区域 但我希望移动到足够的位置 以便整体可见 否则它看起来像是被剪裁了的 我找不到改变这种行为的方法

随机推荐