2014-10-30 96 views
3

我們認爲我們瞭解的TransactionScope和嵌套(transactionscope.requires) - 即.NET嵌套的TransactionScope

 

------------------------------------------------------- 
inner | outer  | 
------------------------------------------------------- 
commit | rollback | no changes are committed 
commit | commit | all changes are committed 
rollback | rollback | no changes are committed 
rollback | commit |  ---- doesn't work ---- 

不過,我想知道,有沒有創造一個TransactionScope,一個嵌套的TransactionScope,依賴的任何方式事務,自定義事務或其他什麼,回滾提交場景也適用? -

即你有一些庫函數,無論出於何種原因都有自己的事務,它的父事務是下的。如果內部成功,那麼外部事務可以訪問任何更改,但是如果內部回滾,外部事務仍處於完全可用狀態,並且完全不受內部事務影響,就好像它從未被調用過一樣?

+1

你在這裏要求什麼_ought_直接支持,恕我直言,但顯然不是。 – 2014-10-31 00:08:27

+0

我同意。 - 而且我們已經解決了這個問題,但是在這一點上,它更像是一種知識上的好奇心 - 也就是說,它實際上可以使它像那樣工作嗎?我正在考慮像使用繼承範圍的東西,並且重寫dispose,所以它只會記住它,但接下來的一段代碼會看到數據庫,就好像你提交了事務 - 或者有某種方法可以神奇地捕獲它,然後再創建另一個交易範圍 - 但之後你會失去所有發生的事情。這是一個非常有趣的問題! – 2014-10-31 03:49:09

+1

我相信你會把數據庫事務(它有助於強制執行數據一致性和原子更改)與其他工​​作單元混淆在一起。從數據一致性的角度來看:如果外層依賴於內層(即內層嵌套在外層),那麼內層回滾之後永遠不會想要繼續。如果不是這樣,外部不依賴於內部。在這種情況下,嵌套事務是您的任務的錯誤工具。通過重構,通常可以得到所需結果的更好方法:使用順序事務(不嵌套),搶先檢查(如果內部將通過)等。 – Arkaine55 2015-09-08 15:59:51

回答

5

不,我相信你正在考慮這個錯誤。它的全部仍然只是一個單獨的事務,它只是嵌套允許感興趣的代碼塊投票,如果事務應該成功(不必傳遞事務對象),而不是創建嵌套事務。這就是爲什麼transactionscope上的方法稱爲「完成」而不是「提交」的原因。

編輯從OP

解決意見得到你想要什麼,我認爲你必須創建兩個TS對象,第二個用RequiresNew,然後完成/回滾每個需要。我不知道第一筆交易是否會從第二筆交易中看到變化,您必須自己進行實驗,看看TS能否在這裏獲得幫助。

我明白你想要做什麼,我並不是說你錯了嘗試;如果這就是你的用例需求,那就是它的要求。

但是我不認爲TS是爲這個用例設計的,我認爲引用嵌套事務的文檔是不幸的,因爲它沒有象通常討論的那樣真正嵌套事務(比如在TSQL中)。

TS設計用於更常見的用例,其中組件A & B既做事務性工作,A使用B作爲其工作的一部分,但B也可以獨立使用。 TS允許B始終是事務性的,不管是單獨使用還是作爲A的一部分工作,並且無需傳遞事務對象就可以啓動事務或重用A(因爲A是UoW)。

+0

a)在理論上理解,但我只想知道它是否可以完成 - 正確的嵌套事務 - b)僅僅因爲某個組件發生了故障,並不意味着我總是想讓整個事情失敗,並且c)主要的問題是它使事務處於不良狀態,以致於在它之後的所有事情都失敗。
僅僅因爲我們認爲某件事情不應該完成,沒有理由不看我們是否可以弄清楚如何去做。 – 2014-10-31 03:16:56

+0

@DarrenOakey我已經添加到我的答案,我希望澄清事情。 – Andy 2014-10-31 13:05:12

+0

將內部TransactionScope設置爲RequriesNew是實現目標的方法。但是,根據這篇文章,http://msdn.microsoft.com/en-us/library/ms973865.aspx,「使用TransactionScopeOption.RequiresNew值時應該非常小心,並驗證兩個事務(環境事務和爲你的範圍創建的那個)不會在引起異常和其他提交時引入不一致。「 – 2014-10-31 13:42:20

1

不作爲交易的範圍。

如果您的交易都是針對數據庫資源管理器(這是託管TransactionScope所有用途的絕大多數),那麼您可以利用數據庫功能。數據庫支持事務保存點。實際的實現因數據庫而異,讓我們來談談SQL Server。

您可以利用直接交易保存點在T-SQL,例如見Exception handling and nested transactions

create procedure [usp_my_procedure_name] 
as 
begin 
    set nocount on; 
    declare @trancount int; 
    set @trancount = @@trancount; 
    begin try 
     if @trancount = 0 
      begin transaction 
     else 
      save transaction usp_my_procedure_name; 

     -- Do the actual work here 

lbexit: 
     if @trancount = 0 
      commit; 
    end try 
    begin catch 
     declare @error int, @message varchar(4000), @xstate int; 
     select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE(); 
     if @xstate = -1 
      rollback; 
     if @xstate = 1 and @trancount = 0 
      rollback 
     if @xstate = 1 and @trancount > 0 
      rollback transaction usp_my_procedure_name; 

     raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ; 
    end catch 
end 
go 

此過程模板允許在例外的情況下適度恢復,允許內部工作回滾,而外部工作繼續並承諾。

你可以在託管代碼相同,如使用SqlTransaction.Save()SqlTransaction.Rollback Method (String)

但是,這些都不受System.Transactions API支持。這並不奇怪,考慮到System.Transactions的主要角色之一是管理分佈式事務(多個RM),但數據庫事務保存點與分佈式事務不兼容。