또?! 오랜만입니다 ㅎㅎ 지인이 애드센스 등록을 하셔서 저도 시도를 해보았더니 콘텐츠 부족으로 실패하여 이렇게 새로운 글을 쓰고 있습니다.

어떤 내용을 쓸까 고민을 하다가 블로그를 정리하면서 예전에 썼던 글 중에 그 당시 궁금했던 내용에 대한 답변을 해보고자 합니다.
(벌써 7년이 지났다니 시간이 참 빠릅니다;;)

TransactionScope 그리고 Stored Procedure (2010. 07. 25)
출처: http://resisa.tistory.com/110 [심플하게~]

(중략)...

1. 한 가지 의문점은 SP안에서는 트랜잭션의 Scope 범위(TransactionScopeOption) 지정하는 부분은 없어보이지만 IsolationLevel 대해서는 지정을   있습니다또한 TransactionScope에서도 IsolationLevel 대해서 지정할  있습니다그래서 IsolationLevel 따른 LTM SQLTransaction 관계가 어떻게 될지도 살짝 궁금해집니다. 하지만 실질적으로 이러한 것을 프로젝트에서 정확하게 알고 사용하는 개발자가 얼마나 될지도 의문이며 IsolationLevel 트랜잭션 사이의 잠금(lock) 대한 것이기 때문에 2. 성능보다는 안전성을 중요시하는 우리 나라의 대부분의 프로젝트에서는 ReadCommitted 사용하는 것이 개발자의 정신건강에 이로워 보입니다. ^^

예전에 썼던 글에 은근히 잘못된 내용이 있습니다;;  이유는 이해부족 입니다;;
저는 새로운 기술을 습득하는 과정에서 '정의'를 자신의 방식으로 표현하고 증명하는 과정을 반복합니다. '정의'와 '증명'을 잘못하면 위와 같이 잘못된 글이 나오기도 하지만 경험이 붙으면 증명하는 시간이 짧아지고 단순 실수도 줄어 이해하는 시간이 짧아지고 자신의 표현 방식으로 인하여 오랫동안 기억되는 장점이 있는 방식이라고 생각됩니다. 그럼 잘못된 부분부터 수정해보겠습니다.

=> 1번에서는 개념에 대해서 잘못 설명하고 있습니다. TransactionScopeOption은 TransactionScope클래스의 파라미터로 DB(SP)에는 없는 속성입니다.

=> 2번 대부분의 프로젝트에서 ReadCommitted로 설정할 것이라는 이유는 MSSQL의 기본 IsolationLevel이 ReadCommitted이기 때문입니다. 이 당시에는 IsolationLevel에 대한 이론적인 것만 알고 있었기 때문에 이런 결론을 냈었는데 업그레이드된?! 지금은 대부분의 프로젝트에서는 ReadUncommitted를 사용할 것이라고 생각합니다. 왜냐하면 ReadCommitted로 설정을 하면 DeadLock이 발생하는 구간이 많이 있을 수 있습니다. 그렇기 때문에 직접적으로 ReadUncommitted를 지정하지 않았더라도 이와 동일한 WITH(NOLOCK) 힌트를 많이 사용했을 것이라고 추측됩니다.

그럼 본론으로 들어가서 노란색 부분에 대한 이야기를 풀어보겠습니다.

먼저 트랜잭션을 아래와 같이 2가지 형태로 구분합니다.
1. 로컬 트랜잭션(SQL Transaction)
2. 분산 트랜잭션(DTC Transaction)

1. 로컬 트랜잭션을 세부화 하면 아래와 같이 나눌 수 있습니다.
1.1. TM(Transaction Manager)이 관여하는 SQL Transaction
1.2 TM이 관여하지 않는 SQL Transaction

개념적인 측면에서는 TM의 관여 여부로 나눌 수 있으며 개발적인 측면에서는 프로그램에서 트랜잭션을 관리하는지 DB에서 즉 SP에서 트랜잭션을 관리 여부로 나눌 수 있습니다.

다시 노란색 부분을 보면 SP에서 트랜잭션을 관리하는 부분들이 프로그램에서 트랜잭션을 관리하는 것과 합쳐졌을 경우에 트랜잭션 관리(Connection, IsolationLevel)에 대한 궁금증이였습니다.

프로그램에서 트랜잭션 관리를 하는 방법은 아래와 같습니다.
1. ADO.NET(System.Data.SqlClient.SqlConnection)를 사용하여 직접 BeginTransaction()를 호출하여 사용
2. System.Transactions.TransactionScope를 사용

트랜잭션을 관리하는 1번, 2번 방법의 공통점은 프로그램에서 트랜잭션을 관리하기 때문에 TM이 트랜잭션을  관리한다는 점입니다. 차이점이 바로 이 글의 핵심이 되는 답변으로 IsolationLevel과 관련되어 있습니다. TransactionScope에 IsolationLevel을 지정하여 사용할 때 SP의 IsolationLevel을 변경할 수 없다는 것입니다. IsolationLevel에 대한 위의 네임스페이스를 살펴보면 아래와 같습니다.

1. System.Data.SqlClient.SqlConnection - System.Data.IsolationLevel
2. System.Transactions.TransactionScope - System.Transactions.IsolationLevel

조심스럽게 예측해보면 TransactionScope의 트랜잭션은 DB 트랜잭션이라기보다는 프로그램에서 발생하는 트랜잭션(여기서는 DB 트랜잭션을 포함하는 상위의 트랜잭션의 개념으로 이해)이라고 할 수 있고 IsolationLevel은 트랜잭션 사이의 격리성이기 때문에 프로그램에서 발생하는 트랜잭션에 대한 격리성이지 DB 트랜잭션에 대한 격리성이 아니기 때문에 DB(SP) IsolationLevel을 변경할 수 없는 것입니다.

결론을 맺으면 프로그램에서 DB(SP) 트랜잭션 관리(IsolationLevel)를 하고 싶으면 SqlConnection을 사용하여 직접 트랜잭션을 발생(BeginTransaction())시켜야하며 TransactionScope을 통해서는 DB(SP) IsolationLevel까지는 관리할 수 없다는 것입니다.

Posted by resisa
,
COM+ Transaction과 System.Transaction 네임스페이스 안의 TransactionScope의 트랜잭션 관점에서의 차이점을 어떻게 알고 계시나요? 저는 COM+ Transaction은 무조건 분산 트랜잭션으로 TransactionScope은 ConnectionString에 따라서 로컬 또는 분산 트랜잭션을 사용하는 것으로 알고 있었습니다. 그런데 최근에 COM+ 관련 테스트를 하다가 재미있는 점을 발견하였습니다. COM+ Transaction도 로컬 트랜잭션으로 사용되는 것과 같은 현상(?!)을 보게 되었습니다. 그러면 저에게 이러한 혼란을 준 현상을 SQL Profiler과 Component Services로 트랜잭션을 모니터링 해보도록 하겠습니다.

테스트 환경
 - .NET Framework 4.0
 - Windows 7 64bit Ultimate
 - MS SQL 2008 R1(local에 설치)

먼저 COM+ 관련 예제 코드는 아래와 같습니다.
[Transaction(TransactionOption.Required)]
public class COMTxObject : ServicedComponent
{
    string connStr = "Data Source=(local);Initial Catalog=EFWithSQL;Integrated Security=True;";
    string connStr2 = "Data Source=(local);Initial Catalog=EFWithSQL;Integrated Security=true;";

    [AutoComplete(true)]
    public void SQL_Select()
    {
        string name = Guid.NewGuid().ToString();

        string query = @"
select top 1 [id] from [dbo].[Entity1Set]
";

        using (SqlConnection conn = new SqlConnection(connStr))
        {
            conn.Open();

            SqlCommand cmd = new SqlCommand(query, conn);
            object result = cmd.ExecuteScalar();
            conn.Close();
        }
    }

    [AutoComplete(true)]
    public void SQL_Insert()
    {
        string name = Guid.NewGuid().ToString();

        string query = @"
insert [dbo].[Entity1Set]([Name])
values ('" + name + @"')
select [Id]
from [dbo].[Entity1Set]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
        ";

        using (SqlConnection conn = new SqlConnection(connStr))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(query, conn);
            int result = cmd.ExecuteNonQuery();
            conn.Close();
        }

        SQL_Insert1_1();
        
    }

    void SQL_Insert1_1()
    {
        string name = Guid.NewGuid().ToString();

        string query = @"
insert [dbo].[Entity1Set]([Name])
values ('" + name + @"')
select [Id]
from [dbo].[Entity1Set]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
        ";

        using (SqlConnection conn = new SqlConnection(connStr))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(query, conn);
            int result = cmd.ExecuteNonQuery();
            conn.Close();
        }
    }

    [AutoComplete(true)]
    public void SQL_Insert2()
    {
        string name = Guid.NewGuid().ToString();

        string query = @"
insert [dbo].[Entity1Set]([Name])
values ('" + name + @"')
select [Id]
from [dbo].[Entity1Set]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
        ";

        using (SqlConnection conn = new SqlConnection(connStr))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(query, conn);
            int result = cmd.ExecuteNonQuery();
            conn.Close();
        }

        SQL_Insert2_1();
    }

    void SQL_Insert2_1()
    {
        string name = Guid.NewGuid().ToString();

        string query = @"
insert [dbo].[Entity1Set]([Name])
values ('" + name + @"')
select [Id]
from [dbo].[Entity1Set]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
        ";

        using (SqlConnection conn = new SqlConnection(connStr2))
        {
            conn.Open();
            SqlCommand cmd = new SqlCommand(query, conn);
            int result = cmd.ExecuteNonQuery();
            conn.Close();
        }
    }
}
=> DB는 Entity1Set이라는 테이블에 ID, Name을 컬럼으로 가지고 있으며 ID의 경우에는 int형의 IDENTITY로 지정하여 자동으로 증가하게 되어 있습니다. COM+ 이기 때문에 ServicedComponents를 상속받고 있으며 해당 클래스 어트리뷰트로 TransactionOption이 Required로 지정된 Transaction 어트리뷰트가 지정되어 있습니다. 세 개의 메서드가 존재하는데 하나는 조회를 하는 쿼리이며 두 개는 ConnectionString이 동일한 상태에서의 삽입이고(SQL_Insert()), 다른 하나는 ConnectionString이 다른 상태에서의 삽입(SQL_Insert2())입니다. 각각 메서드 위에는 자동으로 Complete를 지정해주는 AutoComplete라는 어트리뷰트가 선언되어 있습니다. (참고 : COM+에서는 수동으로 Commmit, Rollback를 해주기 위해서 ContextUtil이라는 클래스를 사용하기도 합니다.)
그리고 해당 어셈블리를 강력한 이름으로 서명을 해주고 AssemblyInfo.cs파일에 ComVisible을 true로 변경해 준 후에 빌드를 하고 Regsvcs.exe를 사용해서 COM+ 카달로그에 등록을 해주었습니다.
그러면 조회 메소드(SQL_Select)를 실행하였습니다.
1. SQL Profiler 결과
=> 헛.. 이상합니다. COM+는 분산 트랜잭션을 사용하기 때문에 DTCTransaction이 보여야 하는데 보이지 않습니다.

2. Component Services 결과
=> 헛.. 역시 이상합니다. COM+ Transaction이 발생하였는데 DTCTransaction이 보이지가 않습니다.

이번에는 조회 메소드 안에서 강제로 예외를 발생시켜 보았습니다.
1. SQL Profiler 결과
=> 드디어 DTCTransaction이 보입니다. Rollback이 정상적으로 됩니다.

2. Component Services 결과
=> 역시 Aborted된 트랜잭션의 개수가 보입니다. 헛헛.. 그렇다면 COM+ 트랜잭션이 정상적으로 Commit이 될 경우에는 로컬 트랜잭션을 사용하고 Rollback이 될 경우에는 분산 트랜잭션을 사용한다는 말입니다. 지금까지 COM+ Transaction은 분산 트랜잭션을 사용해서 느리다라고 알 고 있었는데 제가 먼가 새로운 것을 발견한걸까요? ㅎㅎㅎ;;;
여기서 몇 가지 테스트를 더 해보기 하였습니다.
(참고 : Regsvcs로 컴포넌트를 등록해줄 경우에도 DTC를 사용하여 Committed 개수가 증가합니다. 따라서 모든 테스트 전에는 DTC Service를 멈추었다가 다시 시작해주었습니다.)

먼저 로컬 트랜잭션과 분산 트랜잭션 과연 성능의 차이는 얼마나 있는 것일까요? (성능은 환경적인 요인에 따라 다르게 측정되기 때문에 여기서는 단순한 비교(?!)를 통해서 대략 이렇다 정도로만 테스트를 합니다.)
이번에는 조금 더 많이 사용해 본 TransactionScope클래스를 사용해서 테스트를 해보았습니다.
코드는 아래와 같습니다.
Stopwatch watch = new Stopwatch();
            
for (int i = 0; i < 1000; i++)
{
    using (TransactionScope scope = new TransactionScope(System.Transactions.TransactionScopeOption.Required))
    {
        var helper = new SqlHelper();
        watch.Start();
        helper.SQL_Insert();
        //helper.SQL_Insert2();
        scope.Complete();
    }
    watch.Stop();
}
=> SqlHelper클래스는 이전에 사용한 COMTxObject클래스에서 COM+관련 부분만을 제거한 클래스입니다. 주석 처리된 부분을 보면 해당 테스트가 어떻게 될 것인지 아실 수 있습니다. 먼저 동일한 ConnectionString으로 삽입되는 SQL_Insert()메소드를 호출해보고 ConnectionString이 다른 SQL_Insert2()메소드를 호출하여 실행시켜서 로컬, 분산 트랜잭션의 결과를 비교해 보는 것입니다. 실행 시간을 측정하기 위해서 Stopwatch클래스를 사용하였으며 COM+의 객체 생성시간이 더 오래 걸리기 때문에 트랜잭션과 관련이 있는 메소드의 실행시간만을 측정하기 위해서 메소드 실행 전 후로 Start, Stop 메소드를 호출해주고 있습니다.
먼저 로컬 트랜잭션(1000번)으로 처리하였을 경우에는 대략 3~5초 정도의 시간이 걸립니다. 분산 트랜잭션으로 처리하였을 경우에는 대략 6~9초 정도의 시간이 걸렸습니다. SQL Profiler에서는 로컬시에는 TM(Transaction Manger) 분산시에는 DTCTransaction을 사용하는 것으로 보였고 Component Service에서는 로컬 트랜잭션일 경우에는 아무런 반응이 없다가 분산 트랜잭션을 사용할 경우에 아래와 같이 Commited 숫자가 증가하였습니다.
=> 총 5번을 실행(1000*5) 한 결과입니다.

이번에는 COM+ Transaction으로 동일한 테스트를 해보았습니다.
코드는 아래와 같습니다.
Stopwatch watch = new Stopwatch();

for (int i = 0; i < 1000; i++)
{
    var com = new COMPlusLibrary.EFCOMTxObject();
    watch.Start();
    com.SQL_Insert();
    //com.SQL_Insert2();
    watch.Stop();
}
=> SQL_Insert()를 실행시켰을 때 SQL Profiler에서는 TM만 보이며 Component Service에서 역시 아무런 변화가 없습니다. 그런데 로컬 트랜잭션 이였다고 말하기에 한 가지 이상한 점이 있습니다. 실행시간이 조금 더 걸린다는 겁니다. 거의 TransactionScope을 분산 트랜잭션으로 처리하는 것과 비슷한 시간입니다. SQL_Insert2()를 실행시켰을 때 SQL Profilier에서는 DTCTransaction이 보이며 시간은 더 오래 걸립니다. 그래서 해당 부분을 다시 여러번 실행시켜 실행시간을 다시 측정해보았습니다.
   COM+ Transaction TransactionScope 
 로컬 트랜잭션  4.4~6.3  3.7~5.2
 분산 트랜잭션  7.3~10.4  6.1~9.2
=> 1000번씩 실행되는 구문을 20번 실행시켜 보고 최소값과 최대값을 제외하고 실행 시간의 범위를 표시해보았습니다. 여기서는 실행 모드(Ctrl + F5)로 측정한 값입니다. 로컬이든 분산이든 우리가 이미 알고 있듯이 COM+ Transaction보다는 TransactionScope의 성능이 더 뛰어나다고 말할 수 있습니다. (객체의 생성시간을 제외하고 측정한 시간이기 때문에 COM+ Transaction에게 더 유리한(?!) 측정이였습니다.)

2011-02-18 수정내용
성능 관련 측정을 다시 해보니 문제가 될만한 의심되는 부분이 있었습니다. 정확한 결과는 정확한 확인 이후에 다시 올리도록 하겠습니다.


COM+ Transaction 사용시에 로컬 트랜잭션을 사용한다는 것은 DTC를 사용하지 않는다는 말이 될 수도 있다는 생각에 DTC Service를 종료한 이후에 COM+ TransactionOption을 주고 실행해보았습니다. 아래와 같은 결과를 얻을 수 있었습니다.
 TransactionOption DTC 사용 여부 
 Disable  X
 Not Supported  X
 Supported  X
 Required  O
 RequiredNew  O
=> 물론 여기서 Supported 옵션은 해당 클래스(COMTxObject)의 메소드가 실행되기 전에 트랜잭션이 발생된 이후에 실행되었다면 이전 트랜잭션에 참여하기 때문에 DTC를 사용할 수도 있습니다. DTC를 사용해야지만 트랜잭션이 발생한다는 것을 알 수 있습니다. 또한 DTC를 사용했다고 해서 꼭 DTCTransaction이 발생하는 것은 아니라는 점도 알 수 있습니다.

결론을 내기 전에 지금까지 사용된 용어들을 정리해보는 차원에서 유수석님의 글을 참조 하겠습니다.
http://www.simpleisbest.net/archive/2005/08/23/208.aspx

 분산 트랜잭션이란 네트워크에 분산되어 있는 자원들에 대해 트랜잭션을 수행하는 것을 말한다. 예를 들어, 어떤 애플리케이션이 SQL 서버와 오라클에 데이터를 트랜잭션 하에서 수행해야 한다면 분산 트랜잭션을 필요로 할 것이다. 대개의 경우 분산 트랜잭션은 턱시도, 티맥스, 엔트라와 같은 TP 모니터나 COM+, EJB 등과 같은 컴포넌트 기반 미들웨어가 그 기능들을 제공한다.

분산 트랜잭션의 반대되는 개념으로서 로컬 트랜잭션은 단일 자원(데이터베이스)에 대한 커밋과 롤백을 수행하며 1-phase 커밋으로서 트랜잭션을 수행한다. 한편 분산 트랜잭션의 핵심은 2-phase 커밋으로 볼 수 있다. 커밋(Commit)과 취소(Abort)(분산 트랜잭션에서는 롤백(rollback)보다는 abort라는 용어를 사용한다)를 수행하는데 두 단계를 거친다는 말이다. 첫 번째 phase는 준비 단계(prepare phase)로서, 데이터베이스는 커밋을 위한 모든 준비를 수행한다. 분산 트랜잭션에 참여한 모든 데이터베이스가 준비 단계를 성공한 후에야 두 번째 phase인 커밋 단계가 수행되는 것이다. 만약 분산 트랜잭션에 참여한 어느 한 데이터베이스라도 준비 단계를 실패한다면 두 번째 phase는 커밋이 아닌 취소를 수행하게 될 것이다.

이렇게 각 데이터베이스에게 준비 혹은 커밋/취소의 두 단계를 수행하도록 트랜잭션을 제어하는 트랜잭션 관리자를 TM (Transaction Manager)이라 부르며 이는 MSDTC(Microsoft Distributed Transaction Coordinator)가 담당한다. 지금까지 단순히 분산 트랜잭션에 참여하는 ‘데이터베이스’라고 참조했지만 데이터베이스 외에 다른 자원들도 분산 트랜잭션에 참여할 수 있다. 대표적인 예로 MSMQ, COM+의 Shared Property가 이에 해당된다. 따라서 분산 트랜잭션에서는 트랜잭션에 참여하는 각 자원에 대한 관리를 맡는 RM(Resource Manager)이 존재한다. RM의 대표적인 예는 오라클, SQL 서버와 같은 데이터베이스를 들 수 있다.

요약해 보면, COM+ 컴포넌트의 분산 트랜잭션의 관리는 MSDTC와 같은 TM을 통해 수행하며 TM은 트랜잭션에 참여한 RM들(SQL 서버, 오라클, MSMQ 등)에게 2-phase 커밋을 수행한다는 점이다.


지금까지의 여러 가지 테스트 결과를 확인해보면 COM+ Transaction에서도 로컬과 분산 트랜잭션이 모두 발생하며 동일한 ConnectionString일 경우에 정상적으로 Commit이 될 경우에는 로컬 트랜잭션으로 Rollbakc이 될 경우에는 분산 트랜잭션을 사용하는 것으로 알 수 있습니다. 하지만 COM+ Transaction은 TransactionScope를 사용하는 경우보다 성능적인 면에서 떨어지며 TransactionScope의 경우에 동일한 ConnectionString일 경우에 Commit, Rollback의 여부에 상관없이 모두 로컬 트랜잭션이 발생하며 MSDTC 또한 사용하지 않습니다.
Posted by resisa
,
이전 포스트(닷넷 트랜잭션 정리)에서 닷넷 프레임워크 2.0부터 제공해주는 TransactionScope 클래스를 사용하여 Oracle DB에서 트랜잭션을 처리하기 위해서는 Ora MTS가 필요한 것을 알았다. Windows Vista에서 Ora MTS를 사용하여 트랜잭션을 처리하기 위해서는 패치가 필요하다. 다음 표는 운영체제별로 Oracle 10g로 트랜잭션을 처리하기 위해서 필요한 프로그램을 정리해보았다.
                                                                                                                                       (32bit 기준)
 Windows Xp(Server 2000)  Windows Vista(Server 2008)
 Oracle 10g  10.1.0.2  10.2.0.3
 ODAC(Ora MTS)  10.1.0.4.0  10.2.0.2.21
 Patch Set  X  10.2.0.4

Oracle 10g 다운로드 : http://www.oracle.com/technology/software/products/database/index.html
ODAC 다운로드 : http://www.oracle.com/technology/software/tech/windows/odpnet/index.html
Patch Set 다운로드 : https://metalink.oracle.com/CSP/ui/index.html

xp의 경우에는 설치할 때의 그닥 문제가 없다. ODAC만 설치해줘도 TransactionScope를 사용해서 트랜잭션 처리가 가능하다. 하지만 Vista의 경우에는 ODAC 다운로드 링크에서 설치 문서대로 설치를 해줘야 한다.(설치 순서도 지켜 설치하고 ODAC와 Patch Set은 Database가 설치된 Oracle Home디렉토리로 경로를 맞춰서 설치해준다.)

1. Install Oracle Database Client (10.2.0.3.0) for Microsoft Windows Vista and Windows Server 2008.
2. Download ODAC1020221.exe or ODTwithODAC1020221.exe and unzip its contents by running the executable.
3. Run the Oracle Universal Installer (OUI) by launching setup.exe from the "install" directory that was unzipped in Step 2.
4. On the OUI screen named "Specify Home Details" choose the same Oracle Home as in the Step 1 and proceed.
5. Install Oracle Database 10g Release 2 (10.2.0.4.0) Patch Set. This patch can be downloaded from Oracle Metalink.

여기서 ODAC1020221를 설치하려고 하면 javaw.exe 에러가 발생하여 설치 프로그램이 자동으로 종료가 되어버린다. 여러곳에 검색을 해서 해결방법을 찾으려 했지만 모두 실패했다. 네이버에서 MS Office 2007때문에 설치안된다는 것을 처음에 보았는데 말이 안된다는 생각에 해보지 않았다. 다른 Vista가 설치된 PC에 설치해보려고 해도 역시나 같은 에러가 발생하였다. 마지막으로 Office를 지우고 설치를 해보았다. 설치가 되었다 -_-;;
그래서 이제는 되는구나 싶어서 프로그램을 실행시켰더니 Branch 길이가 다르다는 메세지가 떳다. 다른 사람의 말에 귀도 잘기울려야 하고 설치 가이드도 무시하지 말고 꼼꼼하게 잘봐야한다는 생각을 했다 ㅡ.ㅡ;;;
Oracle Metalink는 오라클 온라인 고객지원 사이트라고 생각하면 된다. 이것은 Oracle과 유지보수 계약을 맺으면 CSI라는 넘버를 부여하고 그 아이디를 이용해서 사용자 등록을 한 이후에 관리자가 승인(회사라면 회사내의 특정한 분이 관리자로 임명되어있다.)처리를 해주면 등록한 이메일 주소로 패스워드를 받아서 로그인을 할 수 있다. 여기서 Patch Set를 받아 드디어 설치를 했고 Vista에서도 TransactionScope를 이용해서 트랜잭션을 처리할 수 있었다. 하지만 이 설치과정이 배포할 경우 모든 클라이언트에 해야한다는 면에서 너무나 부담스럽게 느껴졌다.(패치의 용량이 거의 1G다. ㅡ.ㅡ;) 특히나 원래 DB를 MSSQL를 사용하고 있다가 Oracle에 연결하여 어떤 정보를 가져와야 한다거나 하면 모든 PC에 ODAC와 패치를 설치해줘야 한다니 누가 한단 말인가? +_+;
닷넷을 사용하면 웬만하면 MSSQL를 사용하는 것이 좋다는 생각이 들고 당연히 오라클과 같은 다른 DB에 접속을 하여 처리해야 하는 경우에는 웹서비스를 이용해서 서버에만 ODAC와 패치를 설치해주는 것이 어떨까 하는 생각을 해봤다.
Posted by resisa
,

이번 프로젝트를 하면서 트랜잭션에 대해서 다시 한번 생각해보게 되었고 아래의 사이트들을 통해서 좋은 정보를 얻었다.

트랜잭션에 대한 정리를 잘 해놓은 MS의 장현춘 부장님의 블로그 링크이다.
http://kingcrap.com/entry/닷넷-트랜잭션-정리

System.Transactions(TransactionScope)에 대해서 정리를 해놓은 드원테크놀로지의 유경상 수석님의 블로그링크이다.
http://www.simpleisbest.net/articles/996.aspx

위을 내용을 아주 간단히 요약을 해보겠다~
먼저 트랜잭션 처리는 1. 로컬 트랜잭션(수동) 2. 분산 트랜잭션(자동)으로 나뉜다. 두 가지의 방법은 서로 장단점있는데 속도의 측면에서는 로컬 트랜잭션이 편리성 측면에서는 분산 트랜잭션이 좋다. 하지만 TransactionScope를 사용하면 Promotion이라는 기능이 있고(TransactionScope는 트랜잭션이 발생할 때 로컬 또는 분산 트랜잭션인지를 자동으로 처리해주는데 로컬 트랜잭션으로 실행하다가 다른 DB에 접속을 하는 순간에 자동으로 분산 트랜잭션으로 전환이 되는데 이러한 것을 Promotion이라고 한다.) 이러한 Promotion은 MSSQL 2005, 2008에서만 지원을 한다고 한다.
이번에 내가 한 프로젝트에서 DB가 Oracle여서 TransactinoScope를 사용하려고 했더니 oramts.dll이 필요하다며 예외가 발생했다. Ora MTS를 설치하면 TransactionScope를 사용할 수 있었다.

Ora MTS에 대해서는 아래의 링크를 보자.
http://www.simpleisbest.net/archive/2005/08/23/208.aspx

다음은 Ora MTS를 다운받는 링크이다.
http://www.oracle.com/technology/software/tech/windows/ora_mts/htdocs/utilsoft.html

테스트 환경은 윈도우 서버 2003에서 Oracle 9i 클라이언트와 Ora MTS 9.2.0.7.0 버전을 사용해서 해본 결과 TransactionScope를 사용할 수 있었다. 위의 첫번 째 링크(장현춘님)에 가보면 비스타에서도 Ora MTS 10.2.0.4.0버전을 사용해서 분산 트랜잭션으로 MSSQL과 Oracle을 묶어 프로젝트에서 사용하고 있다는 말이 제일 마지막에 나온다. 하지만 비스타에서 Ora MTS(버전:10.2.0.1, 10.2.0.2) 설치 오류가 나서 테스트를 해볼 수가 없었고 Ora MTS 10.2.0.4.0버전을 구할 수도 없었다. 아마 무엇인가 문제가 있어서 배포를 잠시 중단한게 아닌가 싶다.

<<수정일자 : 12월20일>>
Ora MTS 10.2.0.4.0버전이 아니라 Oracle Database 10g Release 2 (10.2.0.4.0) Patch Set의 버전이다. Ora MTS는 10.2.0.2.0를 설치하면 된다. 또한 Ora MTS가 오류가 나는 것의 원인은 Office 2007 때문이였다. 설치를 하다가 javaw.exe프로세스가 종료되었다는 메시지와 함께 설치가 종료되는데 Office를 지우고 설치를 하면 설치가 된다. 이것이 설치되었다고 해서 비스타에서TransactionScope를 사용해서 분산 트랜잭션을 사용할 수 있는 것이 아니다. Oracle Database 10g Release 2 (10.2.0.4.0) Patch Set까지 설치해야한다. Oracle Meta Link에서 이것을 다운을 받을 수 있는데 Meta Link는 오라클과 계약을 맺어 인증번호가 있어야 사용할 수 있다. 패치까지 받고 테스트는 안해봤지만 아마도 될 것이다. 사용자등록을 했는데 관리자가 있어 패스워드를 받아야한다. 참 하나 해보기 힘들다. 차후에 패치를 받고 테스트를 마친후에 정리를 해야할꺼 같다.
Posted by resisa
,