为什么我在锁定的 ActiveRecord 查询生成的 SQL 中看不到 "FOR UPDATE"?

Why don't I see "FOR UPDATE" in the SQL generated by a locked ActiveRecord query?

我正在阅读 "The Rails 5 Way",在第 191 页我看到以下内容:

Pessimistic locking takes place at the database level. The SELECT statement generated by Active Record will have a FOR UPDATE (or similar) clause added to it...

Rails docs 似乎包含相同的信息:

Locking::Pessimistic provides support for row-level locking using SELECT … FOR UPDATE and other lock types.

Chain ActiveRecord::Base#find to ActiveRecord::QueryMethods#lock to obtain an exclusive lock on the selected rows:

Account.lock.find(1) # SELECT * FROM accounts WHERE id=1 FOR UPDATE

作为实验,我想在我的本地机器上重现这个 FOR UPDATE 语句。我知道用悲观锁发起t运行saction的方法是调用.lockclass方法(书上给出了例子t = Timesheet.lock.first)。所以我 运行 玩具 Rails 应用程序 (v 5.1.6) 的 REPL 中的以下代码包含订单 class:

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

我在 SELECTUPDATE 语句中都没有看到 FOR UPDATE。尝试指定悲观锁定时我做错了什么吗?或者我对应该输出什么 SQL 有错误的期望?

我发现我的玩具应用程序正在使用默认的 Rails sqlite 数据库。我创建了一个新的玩具应用程序 (rails new newbie --database=postgresql),创建了一个包含多个实例的新用户模型,然后 运行 User.lock.first,我看到了以下内容:

irb(main):004:0> User.lock.first
  User Load (1.7ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT  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">

如您所见,FOR UPDATE 出现在 SQL 查询中。从 this Stack Overflow answer,我看到默认情况下 SQLite 不支持悲观锁定:

SELECT ... FOR UPDATE OF ... is not supported. This is understandable considering the mechanics of SQLite in that row locking is redundant as the entire database is locked when updating any bit of it.