跳至内容 跳至搜索

指定了与当前事务状态进行交互的接口。

它可以映射到实际的事务/保存点,也可以代表没有事务。

状态

我们说事务在它包装了一个已经被提交或回滚的真实事务时是最终的

如果事务包装了一个未最终确定的真实事务,则事务为打开

另一方面,当事务未打开时,事务为关闭。也就是说,当它代表事务不存在时,或者它包装了一个真实的但已最终确定的事务。

您可以使用open?closed?谓词检查事务是打开还是关闭。

if Article.current_transaction.open?
  # We are inside a real and not finalized transaction.
end

关闭的事务也为blank?

回调

在更新数据库状态后,您有时可能需要执行一些额外的工作,或者在远程系统中反映这些更改,例如清除或更新缓存。

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

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

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

如果事务已经最终确定,尝试注册回调将引发ActiveRecord::ActiveRecordError

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

blank?()

别名:closed?

closed?()

如果事务不存在或已最终确定,则返回 true。

也称为:blank?
# File activerecord/lib/active_record/transaction.rb, line 117
def closed?
  @internal_transaction.nil? || @internal_transaction.state.finalized?
end

open?()

如果事务存在且尚未最终确定,则返回 true。

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

uuid()

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

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