Movatterモバイル変換


[0]ホーム

URL:


Skip to ContentSkip to Search
Ruby on Rails 8.1.1

Module ActiveRecord::Locking::Pessimistic

v8.1.1

Pessimistic Locking

Locking::Pessimistic provides support for row-level locking using SELECT … FOR UPDATE and other lock types.

ChainActiveRecord::Base#find toActiveRecord::QueryMethods#lock to obtain an exclusive lock on the selected rows:

# select * from accounts where id=1 for updateAccount.lock.find(1)

Calllock('some locking clause') to use a database-specific locking clause of your own such as ‘LOCK IN SHARE MODE’ or ‘FOR UPDATE NOWAIT’. Example:

Account.transactiondo# select * from accounts where name = 'shugo' limit 1 for update nowaitshugo =Account.lock("FOR UPDATE NOWAIT").find_by(name:"shugo")yuko =Account.lock("FOR UPDATE NOWAIT").find_by(name:"yuko")shugo.balance-=100shugo.save!yuko.balance+=100yuko.save!end

You can also useActiveRecord::Base#lock! method to lock one record by id. This may be better if you don’t need to lock every row. Example:

Account.transaction do  # select * from accounts where ...  accounts = Account.where(...)  account1 = accounts.detect { |account| ... }  account2 = accounts.detect { |account| ... }  # select * from accounts where id=? for update  account1.lock!  account2.lock!  account1.balance -= 100  account1.save!  account2.balance += 100  account2.save!end

You can start a transaction and acquire the lock in one go by callingwith_lock with a block. The block is called from within a transaction, the object is already locked. Example:

account =Account.firstaccount.with_lockdo# This block is called within a transaction,# account is already locked.account.balance-=100account.save!end

Database-specific information on row locking:

MySQL

dev.mysql.com/doc/refman/en/innodb-locking-reads.html

PostgreSQL

www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE

Methods
L
W

Instance Public methods

lock!(lock = true)Link

Obtain a row lock on this record. Reloads the record to obtain the requested lock. Pass an SQL locking clause to append the end of the SELECT statement or pass true for “FOR UPDATE” (the default, an exclusive row lock). Returns the locked record.

Source:show |on GitHub

# File activerecord/lib/active_record/locking/pessimistic.rb, line 69deflock!(lock =true)ifself.class.current_preventing_writesraiseActiveRecord::ReadOnlyError,"Lock query attempted while in readonly mode"endifpersisted?ifhas_changes_to_save?raise(<<-MSG.squish)              Locking a record with unpersisted changes is not supported. Use              `save` to persist the changes, or `reload` to discard them              explicitly.              Changed attributes: #{changed.map(&:inspect).join(', ')}.            MSGendreload(lock:lock)endselfend

with_lock(*args)Link

Wraps the passed block in a transaction, reloading the object with a lock before yielding. You can pass the SQL locking clause as an optional argument (seelock!).

You can also pass options likerequires_new:,isolation:, andjoinable: to the wrapping transaction (seeActiveRecord::ConnectionAdapters::DatabaseStatements#transaction).

Source:show |on GitHub

# File activerecord/lib/active_record/locking/pessimistic.rb, line 97defwith_lock(*args)transaction_opts =args.extract_options!lock =args.present??args.first:truetransaction(**transaction_opts)dolock!(lock)yieldendend

[8]ページ先頭

©2009-2025 Movatter.jp