Когда в рельсах появляется пессимистичный замок?
Предполагая, что я делаю что-то вроде этого (из руководства по запросам 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/ предполагает, что блочная структура этого метода автоматически разблокируется.