我有一個特例模型,它不應該成爲外部事務的一部分:如何從ActiveRecord中的事務中排除模型?
Outer.Transaction do
...
Inner.create(:blah)
...
end
如何停止內成爲交易的一部分,假設內竟然一無所知哪些具體事務是越來越被拉進?
例如,創建內部交易是不行的,因爲這也將成爲外部交易的一部分。
我想這樣做,因爲內部模型需要立即寫入,而不是等待外部事務提交。
我有一個特例模型,它不應該成爲外部事務的一部分:如何從ActiveRecord中的事務中排除模型?
Outer.Transaction do
...
Inner.create(:blah)
...
end
如何停止內成爲交易的一部分,假設內竟然一無所知哪些具體事務是越來越被拉進?
例如,創建內部交易是不行的,因爲這也將成爲外部交易的一部分。
我想這樣做,因爲內部模型需要立即寫入,而不是等待外部事務提交。
我很好奇什麼會需要這樣的結構!
我想你會努力做到這一點,沒有像你所描述的一些駭客。例如,您可以在mysql中將Inner
的表存儲類型設置爲不支持事務(MyIsam例如)的表存儲類型,同時將其他類的表存儲爲支持事務(YUK!)的某些內容。
如果可以的話,你幾乎可以肯定會更好延遲Inner.create
,直到交易完成後。您可以使用begin來確保始終發生創建。喜歡的東西:
create_inner = false
begin
Outer.transaction.do
...
create_inner = true # instead of Inner.create(:blah)
...
end
ensure
if create_inner
Inner.create(:blah)
end
end
這將成爲,如果你的塊的其餘部分依賴於創建Inner
情況更加複雜。您可以在塊中創建實例,並在塊的末尾將created_inner
設置爲false,這樣,如果代碼無例外地運行,它將在事務中創建,並且您不會再在確保中創建。
如果您想在一般情況下執行此操作,您可以在Inner
上定義類方法以執行塊,但始終會創建Inner
對象。您還需要將after_create
添加到Inner
。當事務成功時,您將依靠塊中的Inner.create
調用來創建它,但如果它回滾了,則需要在之後創建它。例如:
class Inner < ActiveRecord::Base
def self.ensure_created(&block)
Thread.current[:created_inner] = false
begin
block.call
rescue => e
if Thread.current[:created_inner]
Inner.create(:blah)
end
raise e
end
end
def after_create
# Flag that an instance has been created in this thread so
# that if we rollback out of a transaction we can create again
Thread.current[:created_inner] = true
end
你會然後調用它像:
Inner.ensure_created do
Outer.transaction do
...
Inner.create(:blah)
...
end
end
然而,有很多不足之處,以本辦法的,我不知道我會主張它。這很複雜。如果引發ActiveRecord :: Rollback,則異常將不會冒出Outer.transaction
,但會導致不會創建Inner
實例。當兩個或多個調用嵌套時,它將無法正常工作。最後我還沒有徹底測試 - 謹慎使用!
您可以爲Inner定義一個單獨的數據庫連接,然後事務將只應用於Outer的連接。
感謝您的建議!爲了回答他的場景問題,其基本上用於鎖定批量作業任務,其中「內部」是鎖定模型。如果有兩批試圖在第二批時發生故障而不是排隊等候,或者可能會堆積如山。外部事務實際上是停止發生這種故障,導致每個鎖定輪流等待。 – 2010-09-10 19:17:39
我並沒有因爲提供的任何建議而結束,但我將其標記爲「接受的答案」,因爲這是最好的嘗試。多謝你們! – 2010-09-27 04:55:13
@greg malcolm:如果你沒有遵循任何建議......你做了什麼? – marcgg 2010-10-07 12:37:54