[LRUG] Transactions
Andrew Stewart
boss at airbladesoftware.com
Thu Dec 13 04:14:33 PST 2012
Afternoon all,
I have successfully confused myself with (mysql) database transactions – hopefully someone can enlighten me.
Here's the scenario: a book can be checked out from a library. When that happens, the book's state is updated from available to out and a loan record is created recording who checked out the book. The code looks like:
class Book < ActiveRecord::Base
has_many :loans
state_machine initial: 'available' do
state 'available' do
transition on: :transition_check_out, to: 'out'
end
state 'out' do
# ...
end
end
def check_out(person)
ActiveRecord::Base.transaction do
if transition_check_out # (1)
loans.create checked_out_by_id: person.id
else
# (2)
end
sleep 5 # (3)
end
end
end
Notes:
(1) Handled by the state_machine gem. It's equivalent to (AFAIK):
if state == 'available' && update_attributes state: 'out'
(2) I assume the book is already checked out (to this person) thanks to a double-click on the GUI.
(3) The sleep is to make the problem easier to reproduce.
The idea is that if there's a double-click on the check-out form in the GUI, the book won't end up with two loan records representing the same loan in real life. However occasionally and reproducibly I can get two loan records like this:
- Process 1 executes and starts sleeping at (3).
- Process 2 starts a new transaction and cannot see the pending results of process 1's transaction. It (process 2) thinks the book is available and so updates it to out and creates a loan. Process 2 starts sleeping.
- Process 1 commits its transaction.
- Process 2 commits its transaction. There are now two "duplicate" loans.
I've reached the lamentable stage where the more I think about this, the less I understand :p
Any help would be much appreciated.
BTW this follows up:
http://lists.lrug.org/htdig.cgi/chat-lrug.org/2011-November/006652.html
Thanks in advance,
Andy Stewart
More information about the Chat
mailing list