上周,我在作业模型上实施了:view_count 整数列。今天我在比较我的网站和Google分析之间的统计数据。浏览量的数字并不一致(有时会有所不同),我现在变得偏执,也许我已经完成了这个简单的任务。
另一个复杂因素是此操作中的一些条件逻辑。如果有人想提出任何改变,我会愿意更好地编写整个行动。
def show
unless signed_in?
redirect_to jobs_path, status: 301, if @job.end_date < Time.zone.now.to_date
@job.increment! :view_count unless @job.end_date < Time.zone.now.to_date
end
end
在审核了API文档后,我考虑将以下行重写为:
Job.increment_counter(:view_count, @job) unless @job.end_date < Time.zone.now.to_date
那么。
1)有什么不对劲跳出来了吗?
2)哪个更好用:增量!或increment_counter。
我正在使用Postgres作为数据库。任何有用的建议或想法都表示赞赏。
注意:使用 before_filter :show for @job = Job.find(params [:id])
答案 0 :(得分:2)
出错有什么不对吗?是的,increment!
都是错的,不应该使用恕我直言。我为什么这么说?和Rails一样,你必须阅读源代码才能看到正在发生的事情。这就是increment!
的作用:
def increment!(attribute, by = 1)
increment(attribute, by).update_attribute(attribute, self[attribute])
end
increment
做了什么? increment
这样做:
def increment(attribute, by = 1)
self[attribute] ||= 0
self[attribute] += by
self
end
和update_attribute
执行此操作:
def update_attribute(name, value)
name = name.to_s
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
send("#{name}=", value)
save(:validate => false)
end
展开,我们发现您的@job.increment! :view_count
与此相同:
@job.view_count = (@job.view_count || 0) + 1
@job.save(:validate => false)
这里的竞争条件应该是明确的:
@job
。@job
。@job.view_count
并将其写入数据库。@job.view_count
并将其写入数据库。但是Process-2并不知道Process-1后面的view_count
递增,所以Process-1的增量消失了。所以是的,increment!
非常愚蠢,容易丢失数据,我不会将它用于任何事情。
如果您追踪increment_counter
,您会发现它只是update_counters
的包装。如果您阅读update_counters
,您将看到它正确地让数据库完成工作,只需告诉数据库使用大致如此的SQL增加列值:
update t set c = c + 1 where id = x
那应该是可靠的。
摘要:忘记increment!
,decrement!
,increment
和decrement!
存在并改为使用increment_counter
。