0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ActiveRecordにおける楽観的ロックと悲観的ロックの使い方

Last updated at Posted at 2021-12-21

環境

  • Rails 7.0.0
  • Ruby 2.7.5
  • MySQL 5.7

楽観的ロック

lock_version というカラムを用意するだけで利用できます。

$ rails g model user name:string lock_version:integer
$ bundle e rails b:migrate
$ bundle e rails c
irb(main):001:0> User.create!(name: 'Taro')
   (0.9ms)  SELECT sqlite_version(*)
  TRANSACTION (0.1ms)  begin transaction
  User Create (0.5ms)  INSERT INTO "users" ("name", "lock_version", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["name", "Taro"], ["lock_version", 0], ["created_at", "2021-12-20 23:14:45.459194"], ["updated_at", "2021-12-20 23:14:45.459194"]]
  TRANSACTION (3.7ms)  commit transaction
=> #<User:0x00007fe7449a47b8 id: 1, name: "Taro", lock_version: 0, created_at: Mon, 20 Dec 2021 23:14:45.459194000 UTC +00:00, updated_at: Mon, 20 Dec 2021 23:14:45.459194000 UTC +00:00>

lock_version カラムが自動で更新されています。

悲観的ロック

$ rails g model user name:string
$ bundle e rails b:migrate
$ bundle e rails c

lock

発行するクエリに FOR UPDATE 句をつけてくれます。

irb(main):001:0> User.create!(name: 'Taro')
irb(main):002:0> User.lock.find(1)
  User Load (0.9ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 FOR UPDATE

引数にデータベース固有のクエリを与えることもできます。

irb(main):003:0> User.lock('LOCK IN SHARE MODE').find(1)
  User Load (0.8ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 LOCK IN SHARE MODE

lock!

id カラムで行ロックをかけます。

irb(main):004:0> user = User.first
irb(main):005:0> user.lock!
  User Load (0.8ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 FOR UPDATE

with_lock

トランザクションを開始してロックをかけます。

irb(main):006:1* user.with_lock do
irb(main):007:1*   user.name = 'Jiro'
irb(main):008:1*   user.save!
irb(main):009:0> end
  TRANSACTION (0.6ms)  BEGIN
  User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 FOR UPDATE
  User Update (0.9ms)  UPDATE `users` SET `users`.`name` = 'Jiro', `users`.`updated_at` = '2021-12-21 00:30:04.024824' WHERE `users`.`id` = 1
  TRANSACTION (1.5ms)  COMMIT

参考

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?