0
0

Rails lock! のメモ

Last updated at Posted at 2024-01-06

ふとした時に lock! の挙動が気になるのでメモしておく。

前提

  • Postgresql

テスト1

以下のコードを console A, console B 両方に貼り付けて、A -> B の順に実行

ActiveRecord::Base.transaction do
  User.first.lock!
  sleep 10
  puts 'foo'
end

console A

  TRANSACTION (0.1ms)  BEGIN
  User Load (0.8ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 FOR UPDATE  [["id", 4], ["LIMIT", 1]]
foo
  TRANSACTION (2.4ms)  COMMIT
=> nil

console B

select for update が走るが、console A の終了を待ってから sleep 10 が走る

テスト2

# console A
ActiveRecord::Base.transaction do
  User.first.lock!
  sleep 10
  puts 'foo'
end
# console B
User.first.update_confirmation_token!

console A

テスト1と同じ

console B

user の select は走るが、A を待ってから実行される

テスト3

# console A
ActiveRecord::Base.transaction do
  User.first.lock!
  sleep 10
  puts 'foo'
end
# console B
User.first.clients.create!(
  name: 'foo',
)

console A

テスト1と同じ

console B

user の select は走るが、A を待ってから INSERT が実行される

補足

console B は以下にしても同じ

Client.create!(
  user: User.first,
  name: 'foo',
)

テスト4

# console A
ActiveRecord::Base.transaction do
  User.first.lock!
  sleep 10
  puts 'foo'
end
# console B
User.first.clients.last.update(
  name: 'bar',
)

console A

テスト1と同じ

console B

update まで即実行される

テスト5

# console A
ActiveRecord::Base.transaction do
  User.first.lock!
  sleep 10
  puts 'foo'
end
User.first.clients.last.reports.create!(
  date: Date.current,
)

console A

テスト1と同じ

console B

insert が即実行される

参考

行レベルロックは、データの問い合わせには影響を与えません。 行レベルロックは、同じ行に対する書き込みとロックだけをブロックします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0