카테고리

분류 전체보기 (510)
문학 (128)
찬양 콘티(Continuity) (80)
Business as heritage (6)
IT . Web (149)
Photo (127)
etc. (20)
Total357,714
Today33
Yesterday98
*20121219 국치가 회복될 사건이 올 때까지 블로그 양쪽은 조의를 표하는 검정색입니다.
Tistory 로고 이미지 티스토리 가입하기!









블로그 이미지

TransactionScope는 보통 SqlConnection을 밖에서 감싸는 구조로 사용해왔고,
Complete 메소드 호출까지 에러가 없으면 당연히 반영에 아무 문제가 없다고 생각하고 써왔습니다.

일반적으로 사용한 코드 구조는 아래와 같습니다.

using (TransactionScope ts = new TransactionScope())
{
  using (SqlConnection cn = DatastoreConnector.getBasicConnection())
  {
    cn.Open();

    // To-do for success without exception.

    ts.Complete();

    // To-do after success.
  }
}

그런데 작성해서 사용하는 페이지 중 하나가 잘 처리될 때가 있고 어떨 때는 아무런 예외도 발생하지 않는데 적용되지 않을 때가 있어서 '코드의 재구성(범죄의 재구성ㅋㅋ)'을 시도해봤습니다.

뭔가 T-SQL 에러 등이 문제라면 exception을 발생시키던가. Complete까지 무사히 호출하고 반영이 안되는 건 무슨 상황이란 말입니까.

다음은 MSDN에 등록된 TransactionScope 관련 번역문의 일부입니다.


트랜잭션 범위 완료

응용 프로그램이 트랜잭션에서 수행하려는 모든 작업을 완료하면 Complete 메서드를 한 번만 호출하여 트랜잭션을 커밋할 수 있음을 트랜잭션 관리자에 알려야 합니다. using 블록의 마지막 문처럼 Complete를 호출하는 것이 좋습니다.

이 메서드를 호출하지 못하면 트랜잭션이 중단됩니다. 트랜잭션 관리자가 이 상황을 시스템 오류로 해석하거나 트랜잭션 범위에서 예외가 throw된 것으로 해석하기 때문입니다. 그러나 이 메서드를 호출해도 트랜잭션이 반드시 커밋되는 것은 아닙니다. 이 메서드 호출은 단지 트랜잭션 관리자에 상태를 알리는 방법입니다. Complete 메서드를 호출한 후에는 Current 속성을 사용하여 앰비언트 트랜잭션에 더 이상 액세스할 수 없으며 액세스를 시도하면 예외가 throw됩니다.

(상황 1)TransactionScope 개체가 트랜잭션을 처음 만들면 트랜잭션 관리자가 트랜잭션을 커밋하는 실제 작업은 using 블록의 마지막 코드 줄 다음에 수행됩니다. (상황 2)이 개체가 트랜잭션을 만들지 않으면 CommittableTransaction 개체의 소유자가 Commit를 호출할 때마다 커밋이 수행됩니다. 이때 트랜잭션 관리자는 리소스 관리자를 호출하여 Complete 메서드가 TransactionScope 개체에서 호출되었는지 여부에 따라 커밋 또는 롤백 여부를 알립니다.

using 문을 사용하면 예외가 발생해도 TransactionScope 개체의 Dispose 메서드가 호출됩니다. Dispose 메서드는 트랜잭션 범위의 끝을 표시합니다. 이 메서드를 호출한 후에 발생하는 예외는 트랜잭션에 영향을 주지 않습니다. 또한 이 메서드는 앰비언트 트랜잭션을 이전 상태로 복원합니다.

해당 범위가 만든 트랜잭션이 중단되면 TransactionAbortedException이 throw됩니다. 트랜잭션 관리자가 커밋 결정에 도달하지 못하면 TransactionIndoubtException이 throw됩니다. 트랜잭션이 커밋되면 예외가 throw되지 않습니다.


이 페이지는 제가 읽기에만 그런지 몰라도 그다지 명백하게 기술되어있지는 않습니다만(코드와 맞추어서) 아마도 특별한 옵션 없이 TransationScope를 생성했을 경우(기본값 TransactionScopeOption.Required) 기존에 진행 중인 트랜잭션이 있다면 별도 생성 없이 참여하는 형태로 실행될 때는 생성한 개체가 Complete를 호출한다고 해도 이미 실행 중이던 트랜잭션이 Complete를 실행하지 않으면 커밋이 되지 않는다는 말처럼 들립니다. '해당 범위가 만든 트랜잭션이 중단되면' 이라는 애매한 문구는 현재 실행 중인 코드의 트랜잭션만 중단되지 않으면 내가 참여한 트랜잭션이 중단되어도 예외가 throw 되는 것을 전달받지 못한다는 말처럼 들립니다. 이어지는 '트랜잭션 관리자가 커밋 결정에 도달하지 못하면 TransactionIndoubtException이 throw됩니다'라는 표현은 내가 참여한 트랜잭션이 중단될 경우 Indoubt 예외를 전달받을 수 있다는 말처럼 들립니다만..

만약 저의 이해가 바르다면 여러 사용자가 이용하는 웹 시스템에서 TransactionScopeOption.Required는 좋은 옵션이 아니라는 생각이 듭니다. 본래 트랜잭션은 현재 실행 중인 코드가 관심있는 범위의 실행결과에 집중하는 접근이 기본인 것 같은데 다른 코드의 진행여부에 영향을 받는 것은 부적절해보입니다.

그래서 코드를 조금 수정해서 new TransactionScope(TransactionScopeOption.RequiresNew)로 고쳤습니다. 기본값인 Required와 달리 RequiresNew 옵션은 생성 시점에서 참여가능한 트랜잭션이 있거나 말거나 자신이 새 트랜잭션을 생성합니다.

테스트 환경에서는 몇 건의 수정을 동시에 시도 안해서 잘 동작되는 것일 수도 있으니 현업에서의 리포트를 좀 더 받아봐야겠지만 이번 접근이 바른 접근이었다면 나머지 비즈니스 로직에서도 TransactionScope()로 표현된 부분을 TransactionScope(TransactionScopeOption.RequiresNew)로 고쳐야겠습니다. 물론 트랜잭션 수 자체가 늘어나면 관리에 쓰이는 시스템 비용은 증가하겠지만 그래도 이 편이 맞는 것 같습니다.

ps. 제 이해에 보탬을 주실 분들은 댓글로 설명이나 참조 URL 주시면 감사하겠습니다. ^^a

저작자 표시
신고
Posted by One of Remnants

댓글을 달아 주세요

달력

« » 2017.10
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

최근에 받은 트랙백

글 보관함