On Jun 27, 2006, at 11:19 AM, Jonathan del Strother
wrote:> I want to be able to display a number of messages, and guarantee
> that they''re only displayed once. Something like this :
>
> def get_new_messages
> @messages = Message.find(:all, :limit => 5, :conditions =>
''new = 1'')
> @messages.each do |msg|
> msg.new = 0
> msg.save
> end
> end
>
>
> However, there''s a race condition in the above code if two users
> try to access the get_new_messages action at the same time. How
> can I avoid this?
There is no race condition, but concurrent users may get the same
records. To ensure a user has exclusive access to the selected
records, use row locking (recently introduced to edge rails - rake
rails:freeze:edge).
def get_new_messages
Message.transaction do
# select * from messages limit 5 for update
Message.find(:all, :limit => 5, :conditions =>
''new=1'', :lock =>
true).map do |message|
message.new = false
message.save!
message
end
end
end
(Note that mysql locks all rows touched by the index it chooses, not
just those returned, so you''ll suffer heavy lock contention.)
A pleasant way to solve the problem is to avoid it - is there a
better way to track unread messages?
jeremy