Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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

前提条件

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

というのも、

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

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

注意

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

参考

hey-inc
インターネットビジネスの企画・開発・運営
https://hey.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away