[Dbix-class] Insert or Update (was ANNOUNCE: 0.08099_08)
Peter Corlett
abuse at cabal.org.uk
Mon Apr 13 10:20:41 GMT 2009
On 13 Apr 2009, at 09:35, Tim Bunce wrote:
[...]
> If you use SELECT FOR UPDATE then savepoints aren't required for a
> safe
> implementation, right?
No.
update_or_create() currently does the following: it does a SELECT to
retrieve any extant row; if the row exists it then does an UPDATE if
necessary to update any rows that have changed, otherwise it performs
an INSERT. There is a race between the SELECT and the subsequent
UPDATE or INSERT.
SELECT FOR UPDATE creates an exclusive lock on the rows that are
returned until they are UPDATEd. This neatly fixes the race where an
existing row is being updated. It's the intent of SELECT FOR UPDATE,
after all.
Critically though, if the SELECT does not return any rows, nothing is
locked and the race remains. It doesn't block a second process from
also doing a SELECT on the same non-existent row and getting no
results, and then subsequently two processes trying an INSERT and one
failing.
There's also a third case, where it turns out the row hasn't actually
changed, and DBIC skips the UPDATE in that case. However, skpping the
UPDATE causes the lock to remain.
So it looks like this still needs savepoints to do correctly. Of
course, one could always instead do a heroically complex bodge job
that looks really impressive but doesn't actually work.
> (Which is handy, as SELECT FOR UPDATE is more widely supported than
> savepoints.)
The elephant in the room that is MySQL can attack this problem in a
different way, using REPLACE INTO or INSERT ... ON DUPLICATE KEY UPDATE.
More information about the DBIx-Class
mailing list