跳至内容 跳至搜索

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 回调时,重要的是要注意,如果回调引发错误,事务将不会回滚,因为它已经被提交了。仅仅依靠这些来同步多个系统之间的状态可能会导致一致性问题。

方法
A
B
C
O
U

常量

NULL_TRANSACTION = new(nil).freeze
 

实例公共方法

after_commit(&block)

注册一个块,在事务完全提交后调用。

如果没有当前打开的事务,块将立即被调用,除非事务已完成,在这种情况下,尝试注册回调会引发 ActiveRecord::ActiveRecordError

如果事务有父事务,当当前事务提交时,回调会被转移到父事务;当当前事务回滚时,回调会被丢弃。此操作会重复进行,直到达到最外层的事务。

如果回调引发错误,事务将保持提交状态。

# 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

after_rollback(&block)

注册一个块,在事务回滚后调用。

如果没有当前打开的事务,块将不被调用。但如果事务已完成,尝试注册回调会引发 ActiveRecord::ActiveRecordError

如果事务成功提交但有父事务,该回调会自动添加到父事务。

如果所有嵌套事务的整个链都被成功提交,则该块永远不会被调用。

# File activerecord/lib/active_record/transaction.rb, line 104
def after_rollback(&block)
  @internal_transaction&.after_rollback(&block)
end

blank?()

别名: closed?

closed?()

如果事务不存在或已完成,则返回 true。

也别名为: blank?
# File activerecord/lib/active_record/transaction.rb, line 114
def closed?
  @internal_transaction.nil? || @internal_transaction.closed?
end

open?()

如果事务存在且尚未完成,则返回 true。

# File activerecord/lib/active_record/transaction.rb, line 109
def open?
  !closed?
end

uuid()

返回此事务的 UUID,如果事务未打开,则返回 nil

# File activerecord/lib/active_record/transaction.rb, line 121
def uuid
  if @internal_transaction
    @uuid ||= Digest::UUID.uuid_v4
  end
end