2009-04-24 6 views
3

나는 System.Transactions의 기능을 배울 수 있도록 빠른 더미 응용 프로그램을 만들려고합니다. 이 응용 프로그램은 2 개의 다른 SQLExpress DB와 상호 작용합니다. 구성 요소 서비스에서 트랜잭션 통계를 가져 오면 두 번째 연결이 열릴 때 outerScope에서 트랜잭션 시작을 볼 수 있습니다. failOuter가 true이면 트랜잭션은 중단되지만 예외는 발생하지 않습니다. failInner가 true이면 TransactionAbortedException이 발생합니다. MSDN에서TransactionScope을 이해하려고 시도했습니다.

:

응용 프로그램은 트랜잭션에서 수행하고자하는 모든 작업을 완료하면, 당신이 트랜잭션을 커밋 허용하는 트랜잭션 관리자를 알리기 위해 한 번만 완료 메소드를 호출 할 필요가 있습니다. using 블록의 마지막 문으로 Complete에 호출하는 것이 좋습니다.

이 메서드를 호출하지 못하면 트랜잭션 관리자가 트랜잭션을 시스템 오류로 해석하거나 트랜잭션 범위 내에서 throw 된 예외와 동일하게 처리하므로 트랜잭션을 중단합니다.

범위가 트랜잭션을 생성하고 트랜잭션이 중단되면 TransactionAbortedException이 throw됩니다.

그 바탕으로 내 거래 통계는 내가 failOuter 내 응용 프로그램이 true로 설정 실행 중단 된 트랜잭션 매번 보여주는 때문에 내 outerScope가 TransactionAbortedException을 던져 기대. 트랜잭션이 중단 되더라도 예외가 throw되지 않으므로 내 메서드가 true를 반환합니다. 내가 내부 트랜잭션을 중단하지 않으면, 예상대로 동작합니다. 모든 설명이 가장 감사 할 것입니다.

public bool CreateNestedTransaction(bool failOuter, bool failInner) 
    { 
     try 
     { 
      using (TransactionScope outerScope = new TransactionScope()) 
      { 

       /* Perform transactional work here */ 
       using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1")) 
       { 
        SqlCommand myCommand = new SqlCommand(); 
        myConnection.Open(); 
        myCommand.Connection = myConnection; 

        myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)"; 
        myCommand.ExecuteNonQuery(); 
       } 


       using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1")) 
       { 
        SqlCommand myCommand = new SqlCommand(); 
        myConnection.Open(); 
        myCommand.Connection = myConnection; 

        myCommand.CommandText = "update test set Value = Value"; 
        myCommand.ExecuteNonQuery(); 
       } 

       using (TransactionScope innerScope = new TransactionScope()) 
       { 
        using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test2")) 
        { 
         SqlCommand myCommand = new SqlCommand(); 
         myConnection.Open(); 
         myCommand.Connection = myConnection; 

         myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)"; 
         myCommand.ExecuteNonQuery(); 
        } 
        if (failInner == false) { innerScope.Complete(); } 
       } 

       if (failOuter == false) { outerScope.Complete(); } 
      } 
     } 

     catch (TransactionAbortedException) 
     { 
      return false; 
     } 

     return true; 
    } 

답변

7

일반적으로 TransactionScope가 범위를 벗어나 폐기되기 전에 TransactionScope.Complete()를 호출하지 않아 예외가 발생하지 않습니다. 트랜잭션은 조용히 롤백됩니다.

외부 TransactionScope에서 Complete를 호출하려고하는데 내부 TransactionScope가 이미 실패했기 때문에 예외가 발생하여 예외가 발생하므로 예외가 발생합니다.

의미가 있습니까?

하면 연산을 수행 할 경우 외부 트랜잭션이 뭔가를 시도 할 수 있습니다 중단하는 경우 :

// Inside each using TransactionScope(), hhok up the current transaction completed event 
Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted); 

// handle the event somewhere else 
void Current_TransactionCompleted(object sender, TransactionEventArgs e) 
{ 
    // check the status of the transaction 
    if(e.Transaction.TransactionInformation.Status == TransactionStatus.Aborted) 
    // do something here 
} 

나는 일반적인 사용을위한 청소기 패턴이 항상 (전체 호출 할 수있을 거라고 생각하지만) 내부에 TransactionScope를 사용하고 트랜잭션 실패시 특정 작업을 수행하려는 경우 결과 예외를 처리하십시오.

+0

예, 맞습니다. MSDN의 마지막 줄이 나를 떨어 뜨리고 있다고 생각합니다. 내 거래가 중단되고 예외가 발생하는 것을 지켜 보았습니다. 설명 주셔서 감사합니다! 내 외부 예외가 중단되었는지 알 수있는 방법이 있습니까? 이 경우 거짓을 반환하고 싶습니다. –

+0

흠 흥미로운 질문 - 확실하지! 내가 집에 도착했을 때 그것을 확인해 보겠습니다 :) –

+0

예, 일반적으로 사용하게 될 패턴이 아니지만, 할 수있는 방법이 있습니다. 자세한 내용은 편집 된 답변 참조. –

관련 문제