数据保存两次 - 救援

时间:2014-02-05 11:28:57

标签: ruby-on-rails ruby redis resque worker

我走了!我正在使用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:对不起我的英文。

2 个答案:

答案 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

谢谢你们!