search
LoginSignup
24
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

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

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

前提条件

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(...)としたときはロックが解除されるのを待つ。

というのも、

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

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

注意

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

参考

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
What you can do with signing up
24
Help us understand the problem. What are the problem?