Почему не блокируется!остановить другие от обновления? - PullRequest
0 голосов
/ 01 февраля 2019

Это мой класс:

class Plan < ActiveRecord::Base
  def testing
    self.with_lock do
      update_columns(lock: true)
      byebug
    end
  end

  def testing2
    self.lock!
    byebug
  end
end

Я открыл две консоли рельсов.

В первой консоли:

p = Plan.create
=> (basically success)
p.id
=> 12
p.testing2
(byebug) # simulation of halting the execution,
(BYEBUG) # I just leave the rails console open and wait at here. I expect others won't be able to update p because I still got the lock.

На второй консоли:

p = Plan.find(12)
=> (basically said found)
p.name = 'should not be able to be stored in database'
=> "should not be able to be stored in database"
p.save!
=> true # what????? Why can it update my object? It's lock in the other console!

lock! в testing2 не блокируется, в то время как with_lock в тестировании работает.Кто-нибудь может объяснить, почему lock! не работает?

1 Ответ

0 голосов
/ 01 февраля 2019

#lock! использует SELECT… FOR UPDATE для получения блокировки.
Согласно PostgreSQL doc .

FOR UPDATE приводит к тому, что строки, извлекаемые оператором SELECT, блокируются, как если бы они были обновлены.Это предотвращает их блокировку, изменение или удаление другими транзакциями, пока текущая транзакция не завершится.

Вам нужна транзакция, чтобы удерживать блокировку определенной строки.

Попробуйте
console1:

Plan.transaction{Plan.find(12).lock!; sleep 100.days}

console2:

p = Plan.find(12)
p.name = 'should not be able to be stored in database'
p.save 

#with_lock получить транзакцию для вас, поэтому вам не требуется явная транзакция.

(Это документ PostgreSQL. Но я думаю, что другие базы данных реализуют аналогичную логику.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...