发布于 2026-01-06 1 阅读
0

最佳实践:避免竞态条件 🚘💥🚗😰 AWS 安全直播!

最佳实践:避免赛车环境 🚘💥🚗😰

AWS 安全直播!

以下是一些应对比赛状况的场景和技巧。

了解竞赛条件

计算机程序就像一场赛马。它同时执行多项任务,就像赛马比赛中多匹马同时奔跑一样。每匹马代表一个执行线程。这样,一个线程可能负责网络通信,另一个线程可能负责重新绘制用户界面。在竞态条件中,只有当某匹马赢得比赛时,应用程序才能正常运行。例如,如果5号马获胜,应用程序可以正常运行;但如果其他任何一匹马获胜,应用程序就会崩溃。来源:https ://simple.wikipedia.org/wiki/Race_condition

真实案例:多个用户同时预订同一间房间

假设你有一个预订应用程序,假设你有一个Room模型。该rooms表存储了user_id

class Room
  def assign_to_user!(user_id)
    self.user_id = user_id
    self.save!
  end
end
Enter fullscreen mode Exit fullscreen mode

看起来没问题,对吧?不,如果两个用户同时预订同一个房间,很可能会遇到严重问题。原因如下……

第一个提交表单的用户会开启一个数据库事务,而第二个用户在一毫秒后提交表单,开启了另一个数据库事务。现在我们有两个已开启的数据库事务,第二个事务覆盖了第一个事务。这意味着,第一个用户已经支付了房间费用,但房间却被第二个用户预订了,哈哈。想象一下两位房东在大厅里争论的场景,你可能会听到这样的话:“不,房间是我订的!”

为防止这种情况发生,您可以锁定房间桌。

class Room
  def assign_to_user!(user_id)
    # This block is called within a transaction,
    # room is already locked.
    with_lock do
      self.user_id = user_id
      self.save!
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

通过锁定表,即使两个请求同时发生,记录也无法更新,直到数据库锁被释放,这被称为“悲观锁定”

当您知道此类情况极有可能发生在您的应用程序中时,请使用悲观锁。请参阅此处的完整文档和示例: https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

其他情景

以下列举了一些应该实施数据库锁定以避免出现意外竞态条件的情况。

  • 资金交易
  • 预订航班
  • 预订
  • 加密货币交易
  • 赌博

结论与后续步骤

想想你的应用程序的哪些部分需要数据库锁定,希望你能修复这些问题,让所有用户都能获得良好的体验。

如果您有任何疑问或想讨论其他类型的数据库锁定机制(例如乐观锁定) ,请告诉我。

文章来源:https://dev.to/victorhazbun/best-practices-avoid-race-conditions-i31