在Rails应用程序中,用户访问我显示弹出窗口的页面。 我想在每次用户看到弹出窗口时更新记录。
为避免竞争条件,我使用乐观锁定(因此我在弹出表中添加了一个名为lock_version的字段)。
代码很简单:
# inside pages/show.html.erb
<%= render @popup %>
# and inside the popup partial...
...
<%
Popup.transaction do
begin
popup.update_attributes(:views => popup.views + 1)
rescue ActiveRecord::StaleObjectError
retry
end
end
%>
问题是很多用户访问该页面,并且mysql超过锁定超时。
所以网站冻结了,我收到了很多这样的错误: 超过锁定等待超时;尝试重新启动交易
那是因为有很多未决请求尝试使用过时的lock_version值更新记录。
如何解决我的问题?
答案 0 :(得分:0)
您可以使用increment_counter,因为它会生成一个SQL UPDATE查询而不会锁定。
但我认为在你的情况下使用像Redis这样的任何键值数据库来存储和更新你的弹出计数器会更好,因为它可以比SQL DB更快地完成它。
答案 1 :(得分:0)
如果你不能采用像他们的回复中提到的@maxd这样的方法,你可以利用Sidekiq之类的异步库来处理这些类型的请求(其中他们只需要在工作队列)。
<强> LIB / some_made_up_class.rb 强>
def increment_popup(popup)
Popup.transaction do
begin
popup.update_attributes(:views => popup.views + 1)
rescue ActiveRecord::StaleObjectError
retry
end
end
end
然后,在另一段代码中(您的控制器,服务或视图(在视图层中放置逻辑不太理想)。
SomeMadeUpClass.delay.increment_popup(popup)
# OR you can schedule it
SomeMadeUpClass.delay_for(1.second).increment_popup(popup)
这实际上会影响您的插页排队,同时释放您的页面,理论上可以帮助减少您的点击时间等等。
虽然它不仅仅是添加像Sidekiq这样的库(gem)和我在这里的示例代码,但我认为异步库/工具将有很大帮助。