Почему я не вижу «FOR UPDATE» в SQL, сгенерированном заблокированным запросом ActiveRecord? - PullRequest
0 голосов
/ 04 ноября 2018

Я читаю "The Rails 5 Way", и на странице 191 я вижу следующее:

Пессимистическая блокировка происходит на уровне базы данных. ВЫБОР оператор, сгенерированный Active Record, будет иметь значение UPDATE (или похоже) добавлен пункт ...

Документы Rails содержат ту же информацию:

Locking :: Pessimistic обеспечивает поддержку блокировки на уровне строк, используя ВЫБРАТЬ… ДЛЯ ОБНОВЛЕНИЯ и других типов блокировки.

Цепочка ActiveRecord :: Base # найти ActiveRecord :: QueryMethods # заблокировать получить эксклюзивный замок на выбранные строки:

Account.lock.find(1) # ВЫБРАТЬ * ИЗ СЧЕТОВ, ГДЕ id = 1 ДЛЯ ОБНОВЛЕНИЯ

В качестве эксперимента я хотел воспроизвести это утверждение FOR UPDATE на моей локальной машине. Я знаю, что способ инициировать транзакцию с пессимистической блокировкой - это вызвать метод класса .lock (в книге приведен пример t = Timesheet.lock.first). Поэтому я запустил следующий код в REPL игрушечного приложения Rails (v 5.1.6), которое содержит класс Order:

irb(main):015:0> Order.transaction do       
irb(main):016:1* o1 = Order.lock.first
irb(main):017:1> o1.update_attributes(name: 'Foo Bar')
irb(main):018:1> end

Это привело к следующему выводу:

(0.3ms)  begin transaction
Order Load (0.2ms)  SELECT  "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT ?   [["LIMIT", 1]]
SQL (1.1ms)  UPDATE "orders" SET "name" = ?, "updated_at" = ? WHERE "orders"."id" = ?  [["name", "Foo Bar"], ["updated_at", "2018-11-04 03:01:35.593868"], ["id", 1]]
(0.4ms)  commit transaction
=> true

Я не вижу FOR UPDATE ни в операторах SELECT, ни UPDATE. Я делаю что-то не так при попытке указать пессимистическую блокировку? Или у меня неверное ожидание того, какой SQL должен выводиться?

1 Ответ

0 голосов
/ 05 ноября 2018

Я понял, что мое игрушечное приложение использует базу данных Rails sqlite по умолчанию. Я создал новое игрушечное приложение (rails new newbie --database=postgresql), создал новую модель User с несколькими экземплярами и запустил User.lock.first, и увидел следующее:

irb(main):004:0> User.lock.first
  User Load (1.7ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 FOR UPDATE  [["LIMIT", 1]]
=> #<User id: 1, name: nil, phone: nil, created_at: "2018-11-05 01:28:23", updated_at: "2018-11-05 01:28:23">

Как видите, в запросе SQL появляется FOR UPDATE. Из этого ответа на переполнение стека я вижу, что по умолчанию SQLite не поддерживает пессимистическую блокировку:

ВЫБРАТЬ ... ДЛЯ ОБНОВЛЕНИЯ ... не поддерживается. Это понятно учитывая механику SQLite в этой блокировке строк является избыточным поскольку вся база данных блокируется при обновлении любого ее бита.

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