跳至內容 跳至搜尋

類別 指定用於與目前交易狀態互動的介面。

它可以對應到實際的交易/儲存點,或表示沒有交易。

狀態

當交易封裝一個已提交或回滾的真實交易時,我們說這是一個已完成交易。

如果交易封裝一個尚未完成的真實交易,則該交易為開啟狀態。

另一方面,如果交易未開啟,則該交易為關閉狀態。也就是說,當它表示缺少交易,或封裝一個真實的但已完成的交易時。

您可以使用 open?closed? 謂詞來檢查交易是否已開啟或已關閉。

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

已關閉的交易也是「空白」的。

呼叫回函

在更新資料庫狀態後,您有時可能需要執行一些額外的任務,或在遠端系統中反映這些變更,例如清除或更新快取。

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