ActiveRecord и транзакции между `before_save` и` save` - PullRequest
0 голосов
/ 16 апреля 2010

У меня есть некоторая логика в before_save, при которой (только), когда выполняются некоторые условия, я позволяю создать новую строку с special_number, равным максимальному special_number в базе данных + 1. (Если условия не выполняются затем я делаю что-то другое, поэтому я не могу использовать автоинкремент)

Меня беспокоит то, что два потока, действующих в этой базе данных одновременно, могут выбрать один и тот же special_number, если второй выполняется при сохранении первого. Есть ли способ заблокировать базу данных между before_save и завершением сохранения, но только в некоторых случаях? Я знаю, что все транзакции отправляются в транзакциях, это поможет мне?

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 Ответ

1 голос
/ 16 апреля 2010

Если специальное число всегда увеличивается на 1, и у вас не может быть «пробелов», и оно сохраняется в БД, вы можете использовать select для обновления:

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

Вы можете прочитать об этом здесь: выбрать для обновления

Обратите внимание, что она блокирует БД, поэтому у вас может возникнуть проблема с производительностью, если у вас много обновлений для специального номера.

Если вы не возражаете против пробелов в специальном num (в случае неудачной транзакции), то простой способ - использовать функцию memcahced "inc", так как она преформируется очень и очень быстро:

...