2014-10-30 4 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_, чтобы поддерживать его напрямую, ИМХО, но, по-видимому, нет. –

+0

Согласен. - и мы уже работали над этим, но на данный момент это скорее интеллектуальное любопытство - то есть на самом деле это невозможно сделать, чтобы он работал так? Я думал о чем-то вроде использования унаследованной области и переопределял распоряжение, поэтому он ничего не делает, кроме своего запоминания, но затем следующий бит кода видит базу данных так, как будто вы совершили транзакцию, или каким-то образом волшебным образом ее поймать , и впоследствии создавая еще одну область транзакций, но затем вы теряете все, что было до нее. Это довольно интересная проблема! –

+1

Я считаю, что вы вводите в заблуждение транзакции базы данных (которые помогают обеспечить согласованность данных и атомные изменения) с чем-то другим, например, единицами работы. С точки зрения согласованности данных: если внешний зависит от внутреннего (т. Е. Внутреннего вложенного в внешний), вы никогда не захотите продолжать работу после внутреннего отката. Если это не так, внешний не зависит от внутреннего. В этом случае вложенные транзакции являются неправильным инструментом для вашей задачи. С рефакторингом вы обычно можете получить желаемый результат лучше: используйте последовательные транзакции (не вложенные), превентивные проверки (если внутренняя пройдет) и т. Д. – Arkaine55

ответ

5

Нет, и я считаю, что вы думаете об этом неправильно. Все это всего лишь одна транзакция, а именно то, что вложенность позволяет заинтересованным блокам кода голосовать, если транзакция будет успешной (без необходимости передавать объект транзакции), а не для создания вложенных транзакций. Вот почему метод на транзакции называется Complete, а не Commit.

Edit для решения комментариев от OP

Чтобы получить то, что вы хотите, я думаю, вы должны создать два TS объектов, второй с RequiresNew и затем Complete/откатить каждый по мере необходимости. Я не знаю, увидит ли в первой транзакции изменения со второго или нет, вам придется экспериментировать самостоятельно и посмотреть, может ли TS помочь.

Я понимаю, что вы пытаетесь сделать, и я не говорю, что вы ошибаетесь, пытаясь это сделать; если это то, что требует ваш случай использования, то это то, что он требует.

Однако я не верю, что TS предназначен для этого прецедента, и я думаю, что документация, относящаяся к вложенным транзакциям, является неудачной, поскольку ее не совсем вложенные транзакции, как обычно обсуждаются (например, в TSQL).

TS предназначен для более распространенного случая использования, когда компоненты A & B оба выполняют транзакционную работу, A использует B как часть своей работы, но B также может использоваться независимо. TS позволяет B всегда быть транзакционным, независимо от того, используется ли он самостоятельно или как часть работы A и либо запускает транзакцию, либо повторно использует A (поскольку A является UoW), без необходимости передавать объект транзакции.

+0

a) понимаю теоретически, но я просто хочу знать, можно ли это сделать - правильные вложенные транзакции - б) только из-за того, что компонент чего-то терпит неудачу, не означает, что я всегда хочу провалить все это, и в) основная проблема заключается в том, что он оставляет транзакцию в изворотливом состоянии, так что все после ее сбоя ,
Просто потому, что мы думаем, что что-то не должно быть сделано, не причина не видеть, можем ли мы понять, как это сделать. –

+0

@ DarrenOakey Я добавил к своему ответу, который, надеюсь, прояснит ситуацию. – Andy

+0

Наличие внутреннего TransactionScope для RequriesNew - это способ достижения вашей цели. В статье, однако, http://msdn.microsoft.com/en-us/library/ms973865.aspx: «Вы должны быть предельно осторожны при использовании значения TransactionScopeOption.RequiresNew и убедитесь, что две транзакции (внешняя транзакция и тот, который создан для вашей сферы действия) не вводит несогласованность, если кто-то прерывает, а другой совершает ». –

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).

Однако ни один из них не поддерживается API System.Transactions. что неудивительно, учитывая, что одной из основных функций System.Transactions является управление распределенными транзакциями (несколькими RM), но точки сохранения транзакций базы данных несовместимы с распределенными транзакциями.

Смежные вопросы