Когда в рельсах появляется пессимистичный замок?

Предполагая, что я делаю что-то вроде этого (из руководства по запросам Active Record)

Item.transaction do  
  i = Item.first(:lock => true)  
  i.name = 'Jones'  
  i.save 
end 

Блокировка автоматически снимается в конце транзакции? Я посмотрел руководство по активным запросам и документы ActiveRecord:: Locking:: Pessimistic и не смог найти, где прямо указано, где снята блокировка.

3 ответа

Решение

Блокировка - это не функция рельсов, а просто добавление оператора блокировки в запрос, который будет зависеть от используемой вами базы данных. Пессимистическая блокировка принимает "пессимистический" взгляд, полагая, что каждый запрос подвержен коррупции. Таким образом, он будет блокировать выбранные строки, пока вы не закончите с транзакцией. так что Lock > query > unlock. Несмотря на то, что они достаточно согласованы между базами данных, было бы неплохо прочитать документацию по базе данных, которую вы используете для любых специфических для базы данных вещей, которые вы должны знать.

Вот хорошая тема по поводу оптимистической и пессимистической блокировок, которая объясняет это лучше, чем я. Оптимистическая и пессимистическая блокировка

Да, блокировка автоматически снимается в конце транзакции, потому что этот вид блокировки применим только к транзакциям. Блокировать запись таким способом (пессимистическая блокировка) вне транзакции не имеет смысла.

Пессимистичные блокировки применяются на уровне БД.

Ниже приведено описание с примерами для mysql: http://dev.mysql.com/doc/refman/5.0/en/innodb-lock-modes.html

Я признал проблему с пессимистической блокировкой внутри транзакции во время тестов rspec. По какой-то причине в разных системах (я обнаружил это из-за того, что CI не смог запустить spec) запись все еще заблокирована и не может быть получена.

Итак, код и пример rspec приведены ниже.

class FooBar
  def foo
    Model.with_lock do
      model.update(bar: "baz")
    end
  end
end

красный пример

it "updates with lock" do
  expect { Foobar.foo }.to change { model.reload.bar }.to("baz")
end

но правильный зеленый пример должен выглядеть так

it do "updates with lock" do
  Foobar.foo
  expect(model.reload.bar).to eq("baz")
end

Я полагаю, что вы хотите, чтобы блок "гарантировать" был уверен, что блокировка снята.

http://ruby-doc.org/core/classes/Mutex.src/M000916.html имеет:

  def synchronize
    lock
    begin
      yield
    ensure
      unlock
    end
  end

http://yehudakatz.com/2010/02/07/the-building-blocks-of-ruby/ предполагает, что блочная структура этого метода автоматически разблокируется.

Другие вопросы по тегам