2009-08-13 3 views
23

대 SqlTransaction 나는 "상속"한 약간의 C# 방법에서는 ADO.NET SqlCommand 개체를 만들고 항목의 목록을 통해 루프 데이터베이스 (SQL 서버 2005)에 저장한다.리팩토링 ADO.NET - TransactionScope에

지금까지 기존의 SqlConnection/SqlCommand 방식이 사용되었고 모든 것이 제대로 작동하는지 확인하기 위해 이전 항목을 삭제 한 다음 새 항목을 삽입하는 두 단계가 ADO.NET SqlTransaction으로 래핑되었습니다.

using (SqlConnection _con = new SqlConnection(_connectionString)) 
{ 
    using (SqlTransaction _tran = _con.BeginTransaction()) 
    { 
     try 
     { 
     SqlCommand _deleteOld = new SqlCommand(......., _con); 
     _deleteOld.Transaction = _tran; 
     _deleteOld.Parameters.AddWithValue("@ID", 5); 

     _con.Open(); 

     _deleteOld.ExecuteNonQuery(); 

     SqlCommand _insertCmd = new SqlCommand(......, _con); 
     _insertCmd.Transaction = _tran; 

     // add parameters to _insertCmd 

     foreach (Item item in listOfItem) 
     { 
      _insertCmd.ExecuteNonQuery(); 
     } 

     _tran.Commit(); 
     _con.Close(); 
     } 
     catch (Exception ex) 
     { 
      // log exception 
      _tran.Rollback(); 
      throw; 
     } 
    } 
} 

최근에는 .NET TransactionScope 클래스에 대해 많이 읽었으며 궁금한 점이 있습니다. 나는

using (TransactionScope _scope = new TransactionScope()) 
{ 
    using (SqlConnection _con = new SqlConnection(_connectionString)) 
    { 
    .... 
    } 

    _scope.Complete(); 
} 
당신이 선호하는 무엇

, 왜 사용으로 전환하여 아무것도 (일기 좋게, 속도, 안정성)을 얻을 것인가?

마크

답변

14

기존 코드를 TransactionScope으로 바꾸면 즉시 어떤 것도 얻을 수 없습니다. 유연성을 제공하기 때문에 향후 개발에 사용해야합니다. 앞으로 ADO.NET 호출 이외의 것을 트랜잭션에 쉽게 포함시킬 수 있습니다.

BTW, 당신의 게시 된 예에서 SqlCommand 인스턴스는 using 블록에 있어야합니다.

+0

그래, 고마워 존 - 그리고 네, 맞아 -이 예제에서는 using() 블록 (아직!)에 SqlCommand가 없다 -이 작업이 진행 중이다 :-) –

+0

re : SQLCommand using, there is any 가비지 컬렉션 이외의 다른 이유 : 예 : Dispose()는 SQLConnection에 대해 Close() 메서드를 호출하므로 Dispose()는 SQLCommand 메서드를 호출합니까? –

+3

클래스가'IDisposable'을 구현하고,이 클래스의 인스턴스를 생성하면, 그 클래스에 Dispose를 호출해야합니다. 가장 간단한 방법은'using' 블록을 사용하는 것입니다. 나는 항상 그것을 구현하는 습관에 빠져있는 것이 가장 좋습니다. –

9

마이크로 소프트는 트랜잭션 범위를 사용하는 것이 좋습니다 :

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

기본적인 아이디어는 트랜잭션 범위가 당신을 위해 "주변의 트랜잭션 (transaction) 문맥이"관리하는 것입니다. 먼저 하나의 데이터베이스와 대화하고 SQL 트랜잭션을 수행 한 다음 데이터베이스 번호 2와 대화하고 분산 트랜잭션으로 트랜잭션을 상승시킵니다.

트랜잭션 범위가 작동하므로 배관이 아닌 시스템의 기능에 집중할 수 있습니다.

편집

그 범위 내에서 트랜잭션 범위 모두를 사용는 트랜잭션이 적용됩니다. 따라서 명령 행을 트랜잭션에 연결하는 코드 행을 저장하십시오. 이것은 가능한 오류의 원인입니다. 예를 들어,이 행을 잊어 버렸을 가능성이 1000 번이라면 누락 될 수 있습니다.

편집 2

아래 Triynko에 의견에 동의합니다. 그러나 Entity Framework를 사용하여 EF는 자동으로 연결을 닫고 다시 열어 트랜잭션에 등록합니다. 물리적으로 연결을 더 이상 닫지 않으며 연결 풀에 놓고 새로운 연결을 얻습니다.이 연결은 동일한 연결이거나 다른 연결 일 수 있습니다.

+0

확인. 그 덕분입니다. 그러나 ADO.NET 임베디드 트랜잭션 대신 TransactionScope()를 사용하려면 모든 것을 리팩토링하면 어떤 이점이 있습니까? 그 노력이 그만한 가치가 있는지 묻는 것만으로도 그걸 얻을 수 있습니까? –

+8

"트랜잭션 범위를 사용하면 해당 범위 내의 모든 항목이 트랜잭션의 적용을받습니다." 아니, 모든 것이 보상되지 않습니다. 범위에 등록 된 연결에 대해 발행 된 명령 만 범위의 영향을받습니다. 범위에서 열면 연결이 자동으로 범위에 등록됩니다. 그렇지 않으면 이미 열려있는 연결이 SqlConnection.EnlistTransaction을 호출하여 만든 후 수동으로 범위에 참여해야합니다. 예를 들어, 연결을 연 다음 트랜잭션 범위를 작성하면 명령에 트랜잭션이 포함되지 않습니다. – Triynko

+0

@Triynko : 해당 MSDN 기사에 대한 귀하의 댓글은 훌륭합니다! – abatishchev

6

그냥 트랜잭션 범위를 사용하여주의 때로는 것이다 많은 문제를 우리가 등 DTC 방화벽을 설정하고 같은 서버에서 수행해야 많은 설정이 그래서 SqlTransaction 구현에 저장 더 사용 권장하기 때문이다.

7

저는 TransactionScope를 선호합니다. 모든 시나리오에서 완벽하게 작동하지는 않지만 설명하는대로 더 나은 솔루션입니다.

내 추론 : 트랜잭션의

  1. 입대가 자동으로
  2. 예외의 경우에
  3. 트랜잭션 롤백 결과가 좀 덜 코드와 일반적으로,

함께 자동으로 시스템이 나를위한 세부 사항 중 일부를 다루고 있기 때문에보다 견고한 디자인; 내가해야 할 일이 하나 더 적습니다.

또한 투명한 트랜잭션 등록은 DAL에 중첩 된 메서드가 여러 개있는 경우 특히 유용 할 수 있습니다. 실수로 트랜잭션을 DTC가 필요한 분산 된 개체로 바꾸지 않도록주의해야하지만, 동일한 DB를 가리키고 있어도 여러 SqlConnection을 사용하는 경우 발생할 수 있습니다.

2

가 좋아, 어쩌면이 너무 늦었입니다 ...하지만, 지금은 더 나은 사진을 가지고 있기 때문에 어쨌든, 나는 나의 현재에 많은 어려움을 가진 후

... 관심이있는 사람들을 위해 그것을 적어합니다 내가 TransactionScope을 보니 변함에 따라 변할 수있는 SqlTransaction 기반 접근법 ... TransactionScope의 주된 장점은 입니다. 비즈니스 레이어에서 매우 쉽게 사용할 수 있습니다.

2

늦게 ... 데이터베이스가 중첩 트랜잭션을 지원하지 않는 경우에도 비즈니스 계층에 "중첩 된"트랜잭션을 쉽게 가질 수 있습니다. .NET은 중첩을 제어하고 적어도 하나의 데이터베이스 트랜잭션 (SQL Server 2008 이상의 경우)을 사용하여 종료됩니다. 따라서 더 큰 트랜잭션의 일부로 데이터 액세스 코드를 원래 의도와 다르게 쉽게 재사용 할 수 있습니다.