LoginSignup
26
23

More than 5 years have passed since last update.

Railsで悲観的ロック(PostgreSQLの行レベルロック)

Posted at

悲観的ロックについてよく知らなかったので調べました。

前提条件

Rails 4.2.4
PostgreSQL 9.4

使い方

findする前にlockをつけるだけ。FOR UPDATEというロック処理句が発行される。

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

トランザクションがはられている間ロックする。

Account.transaction do
  account = Account.lock.first
  account.balance -= 100
  account.save!
end

ロックとトランザクションを同時にすることもできる。

account = Account.first
account.with_lock do
  account.balance -= 100
  account.save!
end

動作確認

rails consoleを2つ用意する。

console 1

account = Account.first
account.with_lock do
  sleep 30
end

console 2

Account.lock.first

なお、console 2でhoge.firstとした場合はレコードを取得できるがhoge.first.update(...)としたときはロックが解除されるのを待つ。

というのも、

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

という仕様のためらしい。

注意

同一トランザクション内でロックしながらいろいろレコードいじったりするとデッドロックになる可能性があるので注意したほうがよさそう。

参考

26
23
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
26
23