我走了!我正在使用Ruby on Rails构建一个平台。 我正在使用Resque - Redis来保存一些统计数据,我发现了一些问题。
我必须保存应用程序白天执行操作的次数,例如,如果应用程序运行,我必须保存该应用程序当天运行。问题是多个用户可以同时使用应用程序,现在问题就出现了。
unless stat = self.where(app_id: app_id, day: fire_at.to_date).first
stat = StatsApp.new(app_id: app_id, day: fire_at.to_date)
end
stat.increment(action)
逻辑:如果是白天的第一次,则会创建一个新的注册表,如果没有,则只会在当天增加该操作。
有时候,我可以看到数据库已经保存了两次应用程序,因为我有很多进程在队列中,而且我有10名工作人员正在运行。
任何人都可以帮我避免这个吗?
PS:对不起我的英文。
答案 0 :(得分:1)
发生这种情况的原因是线程并发:
Thread 1: stat = self.where(app_id: app_id, day: fire_at.to_date).first #=> false
Thread 2: stat = self.where(app_id: app_id, day: fire_at.to_date).first #=> false
Thread 2: stat = StatsApp.new(app_id: app_id, day: fire_at.to_date)
Thread 1: stat = StatsApp.new(app_id: app_id, day: fire_at.to_date)
要避免这种情况,您需要使用ActiveRecord事务:
stat = self.transaction do
self.where(app_id: app_id, day: fire_at.to_date).first || StatsApp.create(app_id: app_id, day: fire_at.to_date)
end
ActiveRecord事务是原子的,因此没有线程会在这两个语句之间跳转。
答案 1 :(得分:0)
好吧,几小时后我找到了解决方案!
StatsApp.transaction do
stat = self.where(app_id: app_id, day: fire_at.to_date).lock(true).first || StatsApp.create(app_id: app_id, day: fire_at.to_date)
stat.increment(action)
stat.save
end
谢谢你们!