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

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
48
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

RailsのTransactions、Lock 初心者→中級者へのSTEP17/25

RailsのTransactions、Lock

はじめに

前回のTransactionsの応用で今回はデータのロックについてです

データのロック?

DBにおけるロックとはトランザクションが対象データにロックをかけて占有することです。
これはデータの競合を防ぐためです。
二つのトランザクションが同時に起きると、データに一貫性が持てないことがあります。
例としてはこちらのページがわかりやすかったので、参考にしてください。

Railsでロックするには

実装方法は2つ、lockwith_lockがあります。

    User.transaction do
      user = User.lock.find(1)
      user.update!(name: 'taro')
    end

最初にlockメソッドです。チェインして使います。これでトランザクション中はロックされます。処理中は読み取りは可能です。更新処理等は待たされます。

次に、with_lockメソッドです。こちらはトランザクションとロックが同時にできます。

  user = User.first
  user.with_lock do
    user.update!(name: 'taro')
  end

注意点

今回のロックの仕方は悲観的ロックと呼ばれ、ロックしないとデータは競合するだろうという推測の元するロックのやり方で、厳格なロックとなります。利用できるDBMSはPostgresかMySQLとなりますのでご注意を。

試してみる。

参考記事でもコンソール2つ使ってデータがロックされているか試してたので確認してみます。

irb(main):028:0> user = User.first
irb(main):032:0>    user.with_lock do
irb(main):033:1*       sleep 30      
irb(main):034:1>    end              
   (0.1ms)  begin transaction
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?   [["id", 1], ["LIMIT", 1]]

~~~~~~~~~~30秒後~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   (0.2ms)  commit transaction
=> 30

この間に他のコンソールでuserを更新してみます。

irb(main):026:0> user.update(name: 'locking')
   (0.1ms)  begin transaction
  SQL (0.8ms)  UPDATE "users" SET "updated_at" = ?, "name" = ? WHERE "users"."id" = ?  [["updated_at", "2018-12-17 13:16:12.614654"], ["name", "locking"], ["id", 1]]
   (5045.1ms)  commit transaction
   (2.0ms)  rollback transaction
ActiveRecord::StatementInvalid: SQLite3::BusyException: database is locked: commit transaction

ちゃんとロックされてます。待ち時間が長いので戻されてます。

まとめ

データベースも学び直したくなってきた今日この頃。

参考にしたの

Railsのデータロック
https://qiita.com/merrill/items/d9d41d64df292bd6432a

Active Record Transactions
https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

トランザクションの一貫性を保証するロック
http://www.atmarkit.co.jp/ait/articles/0212/21/news003.html

ActiveRecord::Locking::Pessimistic
https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

Railsで悲観的ロック(PostgreSQLの行レベルロック)
https://qiita.com/upinetree/items/b3329501561268f7678a

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
48
Help us understand the problem. What are the problem?