[C#] 일부 컴퓨터에서 TransactionScope가 MSDTC로 자동 에스컬레이션됩니까?

우리 프로젝트에서는 TransactionScope를 사용하여 데이터 액세스 계층이 트랜잭션에서 작업을 수행하도록합니다. 우리는 최종 사용자의 컴퓨터에서 MSDTC 서비스를 사용하도록 요구 하지 않습니다 .

문제는 개발자 컴퓨터의 절반에서 MSDTC를 비활성화하여 실행할 수 있다는 것입니다. 다른 절반은 활성화해야하거나 “[SERVER]의 MSDTC를 사용할 수 없습니다” 오류 메시지가 나타납니다.

실제로 머리가 긁히고 ADO.NET 트랜잭션 객체를 기반으로하는 자체 트랜잭션 TransactionScope 유사 솔루션으로 롤백하는 것을 진지하게 고려하고 있습니다. 우리 개발자의 절반에서 작동 하고 다른 개발자 에게는 에스컬레이션하는 것과 동일한 코드입니다 .

트랜잭션이 DTC로 에스컬레이션 된 이유추적 에 대한 더 나은 답변을 원했지만 불행히도 그렇지 않습니다.

다음은 에스컬레이션을 시도하는 컴퓨터에서 두 번째 connection.Open ()에서 에스컬레이션하려고 시도하는 문제를 유발하는 샘플 코드입니다.

using (TransactionScope transactionScope = new TransactionScope() {
   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();
         using (SqlDataReader reader = command.ExecuteReader()) {
            // use the reader
            connection.Close();
         }
      }
   }

   // Do other stuff here that may or may not involve enlisting 
   // in the ambient transaction

   using (SqlConnection connection = new SqlConnection(_ConStr)) {
      using (SqlCommand command = connection.CreateCommand()) {
         // prep the command
         connection.Open();  // Throws "MSDTC on [SERVER] is unavailable" on some...

         // gets here on only half of the developer machines.
      }
      connection.Close();
   }

   transactionScope.Complete();
}

우리는 실제로 파헤쳐 이것을 알아 내려고 노력했습니다. 작동하는 머신에 대한 정보는 다음과 같습니다.

  • 개발자 1 : Windows 7 x64 SQL2008
  • 개발자 2 : Windows 7 x86 SQL2008
  • 개발자 3 : Windows 7 x64 SQL2005 SQL2008

작동하지 않는 개발자 :

  • 개발자 4 : Windows 7 x64, SQL2008 SQL2005
  • 개발자 5 : Windows Vista x86, SQL2005
  • 개발자 6 : Windows XP X86, SQL2005
  • 내 홈 PC : Windows Vista Home Premium, x86, SQL2005

문제를 해결하기 위해 모든 컴퓨터에 Microsoft Update에서 제공하는 모든 항목이 완전히 패치되었다고 덧붙여 야합니다.

업데이트 1 :

해당 MSDN 거래 에스컬레이션 페이지에 다음 조건으로 인해 거래가 DTC로 에스컬레이션 될 수 있음이 명시되어 있습니다.

  1. 단일 단계 알림을 지원하지 않는 하나 이상의 영구 리소스가 트랜잭션에 참여합니다.
  2. 단일 단계 알림을 지원하는 둘 이상의 영구 리소스가 트랜잭션에 참여합니다. 예를 들어, 단일 연결에 참여한다고해서 트랜잭션이 승격되지는 않습니다. 그러나 데이터베이스에 대한 두 번째 연결을 열면 데이터베이스가 참여하게됩니다. System.Transactions 인프라는 트랜잭션에서 두 번째 지속 가능한 리소스임을 감지하고이를 MSDTC 트랜잭션으로 에스컬레이션합니다.
  3. 트랜잭션을 다른 응용 프로그램 도메인이나 다른 프로세스에 “마샬링”하는 요청이 호출됩니다. 예를 들어, 응용 프로그램 도메인 경계를 가로 지르는 트랜잭션 개체의 직렬화입니다. 트랜잭션 객체는 값에 따라 마샬링됩니다. 즉, 동일한 프로세스에서도 응용 프로그램 도메인 경계를 통과하려고하면 트랜잭션 객체가 직렬화됩니다. 트랜잭션을 매개 변수로 사용하는 원격 메소드를 호출하여 트랜잭션 오브젝트를 전달하거나 원격 트랜잭션 서비스 구성 요소에 액세스 할 수 있습니다. 이렇게하면 트랜잭션이 응용 프로그램 도메인에서 직렬화 될 때처럼 트랜잭션 개체가 직렬화되고 에스컬레이션됩니다. 분배 중이며 로컬 트랜잭션 관리자가 더 이상 적합하지 않습니다.

# 3이 발생하지 않습니다. # 2는 한 번에 하나의 연결 만 있기 때문에 발생하지 않으며 단일 ‘내구성 자원’에 대한 것이기도합니다. # 1이 일어날 수있는 방법이 있습니까? 단상 알림을 지원하지 않는 일부 SQL2005 / 8 구성?

업데이트 2 :

개인적으로 모든 사람의 SQL Server 버전을 다시 조사한 결과 “Dev 3″에는 실제로 SQL2008이 있고 “Dev 4″는 실제로 SQL2005입니다. 그것은 내 동료를 다시는 신뢰하지 말라고 가르쳐 줄 것입니다. 😉 이러한 데이터 변경으로 인해 문제가 발견 된 것 같습니다. SQL2008에는 SQL2005에없는 많은 기능이 포함되어 있기 때문에 SQL2008 개발자는 문제가 발생하지 않았습니다.

또한 SQL2005를 지원할 예정이므로 이전과 같이 TransactionScope를 사용할 수 없으며 TransactionScope를 사용하려면 단일 SqlConnection 객체를 전달해야합니다. SqlConnection을 쉽게 전달할 수없는 상황에서 문제가있는 것 같습니다 … 전 세계 SqlConnection 인스턴스의 냄새가납니다. 좌석!

업데이트 3

질문에서 명확히하기 위해 :

SQL2008 :

  • 위의 샘플 코드에서 설명한 것처럼 단일 TransactionScope 내에서 여러 연결을 허용합니다.
  • 주의 사항 # 1 : 여러 SqlConnection이 중첩 된 경우 즉, 둘 이상의 SqlConnection이 동시에 열리면 TransactionScope는 즉시 DTC로 에스컬레이션됩니다.
  • 주의 사항 # 2 : 추가 SqlConnection이 다른 ‘내구성 리소스’ (예 : 다른 SQL Server)에 열려 있으면 즉시 DTC로 에스컬레이션됩니다.

SQL2005 :

  • 단일 TransactionScope 기간 내에 여러 연결을 허용하지 않습니다. 두 번째 SqlConnection이 열릴 때 /있는 경우 에스컬레이션됩니다.

업데이트 4

이 질문을 더욱 엉망 으로 만드는 데 도움이되고보다 명확하게하기 위해 SQL2005가 단일 DTC로 에스컬레이션 할 수 있도록하는 방법은 다음과 SqlConnection같습니다.

using (TransactionScope transactionScope = new TransactionScope()) {
   using (SqlConnection connection = new SqlConnection(connectionString)) {
      connection.Open();
      connection.Close();
      connection.Open(); // escalates to DTC
   }
}

이것은 나에게 깨진 것처럼 보이지만 모든 호출 SqlConnection.Open()이 연결 풀에서 잡히고 있는지 이해할 수 있다고 생각 합니다.

“왜 이런 일이 일어날 수 있습니까?” SqlTableAdapter를 열기 전에 해당 연결에 대해 SqlTableAdapter를 사용하는 경우 SqlTableAdapter는 연결을 열고 닫으며 이제 다시 열 수 없으므로 트랜잭션을 효과적으로 마무리합니다.

따라서 기본적으로 SQL2005에서 TransactionScope를 성공적으로 사용하려면 첫 번째 TransactionScope가 더 이상 필요하지 않을 때까지 인스턴스화되는 시점부터 열려있는 일종의 전역 연결 개체가 있어야합니다. 전역 연결 개체의 코드 냄새 외에도 연결을 먼저 열고 마지막으로 닫는 것은 가능한 한 늦게 연결을 열고 최대한 빨리 닫는 논리와 상충됩니다.



답변

SQL Server 2008은 연결이 동시에 열려 있지 않으면 여러 “물리적”TCP 연결이 발생하여 에스컬레이션이 필요한 경우 에스컬레이션없이 여러 개의을 SQLConnection하나의 TransactionScope에스컬레이션으로 사용할 수 있습니다 .

일부 개발자에게는 SQL Server 2005가 있고 다른 개발자에게는 SQL Server 2008이 있습니다. 어떤 개발자가 에스컬레이션하고 있는지, 그렇지 않은지를 정확하게 알고 있습니까?

가장 분명한 설명은 SQL Server 2008을 사용하는 개발자가 확대되지 않는 개발자라는 것입니다.


답변

주제에 대한 나의 연구 결과 :

여기에 이미지 설명을 입력하십시오

분산 트랜잭션으로 원치 않는 에스컬레이션 방지를 참조 하십시오.

여전히 Oracle의 에스컬레이션 동작을 조사하고 있습니다.
동일한 DB에 대한 여러 연결에 걸친 트랜잭션이 DTC로 에스컬레이션됩니까?


답변

이 코드 2005에 연결할 때 에스컬레이션을 발생시킵니다.

MSDN에서 설명서를 확인하십시오-http: //msdn.microsoft.com/en-us/library/ms172070.aspx

SQL Server 2008의 승격 가능한 트랜잭션

.NET Framework 및 SQL Server 2005 버전 2.0에서 TransactionScope 내에서 두 번째 연결을 열면 두 연결 모두 동일한 연결 문자열을 사용하더라도 트랜잭션이 전체 분산 트랜잭션으로 자동 승격됩니다. 이 경우 분산 트랜잭션은 불필요한 오버 헤드를 추가하여 성능을 저하시킵니다.

SQL Server 2008 및 .NET Framework 버전 3.5부터는 이전 트랜잭션을 닫은 후 트랜잭션에서 다른 연결을 열면 로컬 트랜잭션이 더 이상 분산 트랜잭션으로 승격되지 않습니다. 이미 연결 풀링을 사용하고 트랜잭션에 참여하는 경우 코드를 변경할 필요가 없습니다.

Dev 3 : Windows 7 x64, SQL2005가 성공하고 Dev 4 : Windows 7 x64가 실패하는 이유를 설명 할 수 없습니다. 그 반대의 방법이 아닙니까?


답변

이 답변이 왜 삭제되었는지 모르겠지만 관련 정보가있는 것 같습니다.

생성 08 aug. 102012-08-17 17:42 Eduardo

  1. 트랜잭션에 자동으로 참여하지 않도록 연결 문자열에서 Enlist = false 를 설정하십시오 .

  2. 트랜잭션 범위의 참여자연결을 수동으로 참여 시킵니다. [ 원본이 오래됨] 또는 수행 : 자동 MSDTC 프로모션을 방지하는 방법 [archive.is]


답변

중첩 연결이 문제인지 확실하지 않습니다. SQL Server의 로컬 인스턴스를 호출하고 있으며 DTC를 생성하지 않습니까 ??

    public void DoWork2()
    {
        using (TransactionScope ts2 = new TransactionScope())
        {
            using (SqlConnection conn1 = new SqlConnection("Data Source=Iftikhar-PC;Initial Catalog=LogDB;Integrated Security=SSPI;"))
            {
                SqlCommand cmd = new SqlCommand("Insert into Log values(newid(),'" + "Dowork2()" + "','Info',getDate())");
                cmd.Connection = conn1;
                cmd.Connection.Open();
                cmd.ExecuteNonQuery();

                using (SqlConnection conn2 = new SqlConnection("Data Source=Iftikhar-PC;Initial Catalog=LogDB;Integrated Security=SSPI;Connection Timeout=100"))
                {
                    cmd = new SqlCommand("Insert into Log values(newid(),'" + "Dowork2()" + "','Info',getDate())");
                    cmd.Connection = conn2;
                    cmd.Connection.Open();
                    cmd.ExecuteNonQuery();
                }
            }

            ts2.Complete();
        }
    }


답변

내부에서 둘 이상의 연결에 액세스하는 경우 TransactionScope는 항상 DTC 트랜잭션으로 에스컬레이션됩니다. 위의 코드가 DTC를 비활성화 한 상태에서 작동 할 수있는 유일한 방법은 연결 풀에서 두 번 동일한 연결을 얻는 경우입니다.

“문제는 개발자 컴퓨터의 절반에서 MSDTC를 비활성화 한 상태에서 실행할 수 있다는 것입니다.” 비활성화되어 있는지 확인하십시오.)


답변

connectionString이 풀링을 false로 설정하지 않았는지 확인하십시오. 그러면 TransactionScope의 각 새 SqlConnection에 대한 새 연결이 생성되어 DTC로 에스컬레이션됩니다.