views:

31

answers:

1

I have some logic in before_save whereby (only) when some conditions are met I let the new row be created with special_number equal to the maximum special_number in the database + 1. (If the conditions aren't met then I do something different, so I can't use auto-increments)

My worry is that two threads acting on this database at once might pick the same special_number if the second is executed while the first is saving. Is there way to lock the database between before_save and finishing the save, but only in some cases? I know all saves are sent in transactions, will this do the job for me?

def before_save
  if things_are_just_right
    # -- Issue some kind of lock?
    # -- self.lock? I have no idea
    # Pick new special_number
    new_special = self.class.maximum('special_number') + 1
    write_attribute('special_number',new_special)
  else
    # No need to lock in this case
    write_attribute('special_number',some_other_number)
  end
end
+1  A: 

If the special number is always increasing by 1, and you cant have "gaps", and it's saved in the db- you can use select for update:

SELECT special_num FROM nums FOR UPDATE;
UPDATE nums SET special_num  = special_num  + 1;

You can read about it here: select for update

Note that it is locking the DB, so you may have a performance issue if you have lots of updates to taht special number.

If you dont mind having gaps in the special num (in case a transaction is failed) an easy way is to use memcahced "inc" function, as it will preform very, very fast :)

amikazmi
I'm not actually using MySQL! (heroku + sqlite3) - I don't think sqlite has an equivalent function?
JP