класс ActiveRecord::Transaction
Class определяет интерфейс для взаимодействия с текущим состоянием транзакции.
Он может отображаться на фактическую транзакцию/точку сохранения или представлять отсутствие транзакции.
Состояние
Мы говорим, что транзакция завершена, когда она оборачивает реальную транзакцию, которая была либо подтверждена, либо отменена.
Транзакция открыта, если она оборачивает реальную транзакцию, которая не завершена.
С другой стороны, транзакция закрыта, когда она не открыта. То есть, когда она представляет отсутствие транзакции или оборачивает реальную, но завершенную.
Вы можете проверить, открыта или закрыта транзакция, с помощью предикатов open? и closed?:
if Article.current_transaction.open? # We are inside a real and not finalized transaction. end
Закрытые транзакции также являются ‘blank?’.
Callbacks
После обновления состояния базы данных иногда может потребоваться выполнить дополнительную работу или отразить эти изменения в удалённой системе, например, очистить или обновить кэш:
def publish_article(article) article.update!(published: true) NotificationService.article_published(article) end
Вышеприведённый код работает, но имеет одну важную ошибку: он больше не работает должным образом, если его вызывать внутри транзакции, так как он будет взаимодействовать с удалённой системой до того, как изменения будут сохранены:
Article.transaction do article = create_article(article) publish_article(article) end
Обратные вызовы, предлагаемые ActiveRecord::Transaction, позволяют переписать этот метод таким образом, чтобы он был совместим с транзакциями:
def publish_article(article)
article.update!(published: true)
Article.current_transaction.after_commit do
NotificationService.article_published(article)
end
end
В приведённом выше примере, если publish_article вызывается внутри транзакции, обратный вызов будет вызван после успешного подтверждения транзакции, а если вызывается вне транзакции, обратный вызов будет вызван немедленно.
Ограничения
При использовании обратных вызовов after_commit важно помнить, что если обратный вызов вызывает ошибку, транзакция не будет отменена, так как она уже была подтверждена. Полная зависимость от них для синхронизации состояния между несколькими системами может привести к проблемам с согласованностью.
Константы
- NULL_TRANSACTION
Общедоступные методы экземпляра
# File activerecord/lib/active_record/transaction.rb, line 85
def after_commit(&block)
if @internal_transaction.nil?
yield
else
@internal_transaction.after_commit(&block)
end
end Регистрирует блок, который будет вызван после полного подтверждения транзакции.
Если в настоящее время нет открытых транзакций, блок вызывается немедленно, если транзакция не завершена, в противном случае попытка регистрации обратного вызова вызывает ActiveRecord::ActiveRecordError.
Если транзакция имеет родительскую транзакцию, обратный вызов передаётся родителю при подтверждении текущей транзакции или отбрасывается при откате текущей транзакции. Эта операция повторяется до тех пор, пока не будет достигнута внешняя транзакция.
Если обратный вызов вызывает ошибку, транзакция остаётся подтверждённой.
# File activerecord/lib/active_record/transaction.rb, line 107 def after_rollback(&block) @internal_transaction&.after_rollback(&block) end
Регистрирует блок, который будет вызван после отката транзакции.
Если в настоящее время нет открытых транзакций, блок не вызывается. Но если транзакция завершена, попытка зарегистрировать обратный вызов вызывает ActiveRecord::ActiveRecordError.
Если транзакция успешно подтверждается, но имеет родительскую транзакцию, обратный вызов автоматически добавляется к родительской транзакции.
Если вся цепочка вложенных транзакций успешно подтверждается, блок никогда не вызывается.
Если транзакция уже завершена, попытка зарегистрировать обратный вызов вызовет ActiveRecord::ActiveRecordError.
# File activerecord/lib/active_record/transaction.rb, line 117 def closed? @internal_transaction.nil? || @internal_transaction.state.finalized? end
Возвращает true, если транзакция не существует или завершена.
# File activerecord/lib/active_record/transaction.rb, line 112 def open? !closed? end
Возвращает true, если транзакция существует и ещё не завершена.
# File activerecord/lib/active_record/transaction.rb, line 124
def uuid
if @internal_transaction
@uuid ||= Digest::UUID.uuid_v4
end
end Возвращает UUID для данной транзакции или nil, если транзакция не открыта.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.