Spec-Zone.ru › Ruby on Rails 5.1

модуль ActiveRecord::Locking::Pessimistic

Locking::Pessimistic предоставляет поддержку блокировки строк с использованием SELECT … FOR UPDATE и других типов блокировок.

Цепочка ActiveRecord::Base#find до ActiveRecord::QueryMethods#lock позволяет получить эксклюзивную блокировку выбранных строк:

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

Вызов lock('some locking clause') позволяет использовать специфичный для базы данных фрагмент блокировки, такой как 'LOCK IN SHARE MODE' или 'FOR UPDATE NOWAIT'. Пример:

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

Вы также можете использовать метод ActiveRecord::Base#lock! для блокировки одной записи по идентификатору. Это может быть предпочтительнее, если вам не нужно блокировать все строки. Пример:

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

Вы можете начать транзакцию и получить блокировку одним действием, вызвав with_lock с блоком. Блок вызывается в рамках транзакции, объект уже заблокирован. Пример:

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

Информация о блокировке строк, специфичная для базы данных:

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

Общедоступные методы экземпляров

lock!(lock = true) Показать исходный код
# File activerecord/lib/active_record/locking/pessimistic.rb, line 61
      def lock!(lock = true)
        if persisted?
          if has_changes_to_save?
            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

Получение блокировки строки для этой записи. Перезагружает запись, чтобы получить запрошенную блокировку. Передайте SQL фрагмент блокировки, чтобы добавить его в конец оператора SELECT, или передайте true для “FOR UPDATE” (по умолчанию, эксклюзивная блокировка строки). Возвращает заблокированную запись.

with_lock(lock = true) { || ... } Показать исходный код
# File activerecord/lib/active_record/locking/pessimistic.rb, line 78
def with_lock(lock = true)
  transaction do
    lock!(lock)
    yield
  end
end

Оборачивает переданный блок в транзакцию, блокируя объект перед выполнением. Вы можете передать фрагмент SQL блокировки в качестве аргумента (см. lock!).

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API