【问题标题】:Is this a race condition issue in Rails 3?这是 Rails 3 中的竞争条件问题吗?
【发布时间】:2012-01-18 10:57:40
【问题描述】:

基本上我有一个 User 模型,它具有某些属性,比如“健康”,另一个 Battle 模型记录了用户之间的所有战斗。用户可以互相打架,一定的概率将决定谁赢。双方在战斗后都会失去生命值。

所以在 Battle 控制器中,我执行了“CREATE”操作,

@battle = Battle.attempt current_user.id, opponent.id

战斗模型中,

def self.attempt current_user.id, opponent_id

  battle = Battle.new({:user_id => current_user.id, :opponent_id => opponent_id})

  # all the math calculation here
  ...

  # Update Health
  ...
  battle.User.health = new_health
  battle.User.save
  battle.save

  return battle

end

回到Battle控制器,我做了...

new_user_health = current_user.health

战斗后获得新的生命值。但是我得到的值是旧的健康值(战斗前的健康值)。

以前有人遇到过这种问题吗???


更新

我只是添加

current_user.reload

行前

new_user_health = current_user.health

这行得通。问题解决了。谢谢!

【问题讨论】:

  • 认为这就是你所面临的:stackoverflow.com/questions/5519741/…
  • 哪一部分令人困惑?是的,这是实际代码,但我只强调主要内容
  • 我编辑了代码,现在不那么混乱了吗?
  • John,在 Ruby 中,类是大写的,常量是全大写的,方法名是小写的(或者,如果你还没有摆脱 Java 的方式,那就是驼峰式)。看到似乎是大写的方法名称是不寻常的。我怀疑,这让@sarnold 感到困惑。
  • 我不会称之为竞争条件,我会称之为更新数据库而不是 current_user。

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-3.1


【解决方案1】:

您似乎正在获取current_user,然后更新battle.user,然后期望current_user 自动获得更新后的值。使用 Rails 的Identity Map 可以实现这种类型的事情,但您需要先阅读一些注意事项。

问题在于,即使这两个对象由数据库中的相同数据支持,您在内存中也有两个对象。刷新信息,您可以拨打current_user.reload

附带说明,这不会被归类为竞争条件,因为您没有使用多个进程来修改/读取数据。在此示例中,您正在读取数据,然后更新内存中不同对象的数据。如果您使用两个线程同时访问相同的信息,则可能会发生争用情况。

另外,您应该使用 battle.user,而不是像 cmets 中提到的韦恩那样使用 battle.User

【讨论】:

  • 这就是我所说的 :) 不过你的更长。 (哦,如果我有五分之一...)+1 拼写出来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-30
  • 2011-10-02
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多