# module ActiveRecord::Locking::Pessimistic

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

Chain `ActiveRecord::Base#find` to `ActiveRecord::QueryMethods#lock` to obtain an exclusive lock on the selected rows:

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

Call `lock('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.transaction do
      # select * from accounts where name = 'shugo' limit 1 for update
      shugo = Account.where("name = 'shugo'").lock(true).first
      yuko = Account.where("name = 'yuko'").lock(true).first
      shugo.balance -= 100
      shugo.save!
      yuko.balance += 100
      yuko.save!
    end

You can also use `ActiveRecord::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 calling `with_lock` with a block. The block is called from within a transaction, the object is already locked. Example:

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

Database-specific information on row locking:

    MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
    PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE

### Public Instance Methods

lock!(lock = true) click to toggle source

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.

    # File lib/active_record/locking/pessimistic.rb, line 61
          def lock!(lock = true)
            if persisted?
              if changed?
                ActiveSupport::Deprecation.warn("              Locking a record with unpersisted changes is deprecated and will raise an
                  exception in Rails 5.2. Use `save` to persist the changes, or `reload` to
                  discard them explicitly.
    ".squish)
              end
              reload(lock: lock)
            end
            self
          end

with_lock(lock = true) { || ... } click to toggle source

Wraps the passed block in a transaction, locking the object before yielding. You can pass the SQL locking clause as argument (see `lock!`).

    # File lib/active_record/locking/pessimistic.rb, line 78
    def with_lock(lock = true)
      transaction do
        lock!(lock)
        yield
      end
    end