[LRUG] Fwd: Transactions

Roland Swingler roland.swingler at gmail.com
Thu Dec 13 04:22:05 PST 2012


And... forward to the list

---------- Forwarded message ----------
From: Roland Swingler <roland.swingler at gmail.com>
Date: Thu, Dec 13, 2012 at 12:20 PM
Subject: Re: [LRUG] Transactions
To: Andrew Stewart <boss at airbladesoftware.com>


Have a look at the optimistic locking in rails - see this class:
http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html

basically, you include a lock_version column on the table, which is
just an incrementing number. When the second transaction tries to
commit, instead of working it will raise an ActiveRecord::StaleObject
error, which you can then deal with (probably by reloading the record
and trying again).

There is also pessimistic locking, which locks the rows at the
database level iirc:
http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html
but I've not used that, and depending on how busy your system gets may
lead to contention for the locks.

Hope that helps.

R

On Thu, Dec 13, 2012 at 12:14 PM, Andrew Stewart
<boss at airbladesoftware.com> wrote:
> 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
> _______________________________________________
> Chat mailing list
> Chat at lists.lrug.org
> http://lists.lrug.org/listinfo.cgi/chat-lrug.org



More information about the Chat mailing list