这使用与 Rich Cavanaugh 的答案相同的概念。我添加了一个父模型,以便更清楚过滤器在做什么。关键是使用线程+单独连接的自动签出/签入。注意:您应该确保您的 :pool 值在您的连接规范中至少设置为 2,具体取决于您将运行的并发线程数。我认为它默认为5。
class Gadget < ActiveRecord::Base
has_many :widgets
end
class Widget < ActiveRecord::Base
belongs_to :gadget
before_create :update_instead
def update_some_record_in_same_model
# the thread forces a new connection to be checked out
Thread.new do
ActiveRecord::Base.connection_pool.with_connection do |conn|
# try this part without the 2 surrounding blocks and it will be rolled back
gadget.touch_count += 1
gadget.save!
end
end.join
end
def some_condition?
true
end
def update_instead
if some_condition?
update_some_record_in_same_model # this is getting rolled back
p [:touch_count_in_filter, gadget.reload.touch_count]
return false # don't create a new record
else
return true # let it continue
end
end
end
测试:
g = Gadget.create(:name => 'g1')
puts "before:"
p [:touch_count, g.reload.touch_count]
p [:widget_count, Widget.count]
g.widgets.create(:name => 'w1')
puts "after:"
# Success means the count stays incremented
p [:touch_count, g.reload.touch_count]
p [:widget_count, Widget.count]
进一步阅读:http ://bibwild.wordpress.com/2011/11/14/multi-threading-in-rails-activerecord-3-0-3-1/