从事务的角度来看,拥有跟踪操作的附属记录比修改单个记录要好得多。
例如,如果您有一个用户可以下“赌注”的系统,那么理所当然会有某种 Bet 类定义两个人之间的赌注。随着用户创建投注,相关列表将会增长。在 Rails 中,它看起来像这样:
class User < ActiveRecord::Base
has_many :bets
has_many :bet_pools,
:through => :bets
end
class Bet < ActiveRecord::Base
belongs_to :user
belongs_to :bet_pool
end
class BetPool < ActiveRecord::Base
has_many :bets
belongs_to :winning_bet
belongs_to :winning_user,
:class_name => 'User',
:through :winning_bet,
:source => :user
end
每个赌注的金额存储在赌注记录中,赌注代表对特定赌注的总赌注,尽管您可能有不同的术语。
当投注结算时,可以通过分配 bet_pool.winning_user 关联来指定获胜者。
如果您想知道用户的“中奖记录”,那么只需将他们中奖的所有投注池汇总并加起来即可。
您不想不断调整用户记录上的某些属性的原因是,两个独立的进程可能想要调整该值,如果 SQL 没有正确实施,您最终可能会出现竞争条件。例如,用户可能会在很短的时间内下注并赢得赌注。
如果用户以 1000 美元开始并且同时进行两项操作,那么可能会发生这种情况:
# Process A intending to add $500
user.balance = user.balance + 500
user.save
# Process B intending to deduct $100
user.balance = user.balance - 100
user.save
按顺序完成,您希望余额从 1000 变为 1500,然后下降到 1400,但第二个过程在加载时以原始值 1000 开始,然后调整为 900 并保存,覆盖结果第一个。
有一些方法,如increment 和 ActiveRecord 的减量,可以帮助解决这类问题,但最好的结果是根据需要简单地制表。