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


284

우리 프로젝트에서는 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가 더 이상 필요하지 않을 때까지 인스턴스화되는 시점부터 열려있는 일종의 전역 연결 개체가 있어야합니다. 전역 연결 개체의 코드 냄새 외에도 연결을 먼저 열고 마지막으로 닫는 것은 가능한 한 늦게 연결을 열고 최대한 빨리 닫는 논리와 상충됩니다.


"주변 거래와 관련이있을 수있는 다른 작업을 수행하십시오"를 확장 할 수 있습니까? 거기에 무엇이 있는가가 코드의 작동 방식에 큰 영향을 미치는가?
RichardOD 2009

2
"한 번에 하나의 연결 만 있기 때문에 # 2는 일어나지 않습니다"-# 2는 두 번째 연결을 동시에 열어야한다고 말하지 않고 동일한 트랜잭션에 참여해야한다고 말합니다.
Joe

3
단일 SqlConnection만으로 에스컬레이션이 발생하는 방법을 보여주는 업데이트 4로 다시보고 해 주셔서 감사합니다. 이것은 단일 SqlConnection 만 사용되도록주의 깊게 확인했지만 정확히 내가 실행 한 것입니다. 그것이 미친 컴퓨터이고 저가 아니라는 것을 아는 것이 좋습니다. :-)
Oran Dennison

연결 풀링과 관련하여 여러 연결 (필요한 경우 중첩)이있는 경우 한 번에 하나씩 열고 닫을 경우 실제 연결 풀 자원 1 개 또는 연결 당 1 개를 사용하는 경우 결정하기 위해 합리화하려고합니다. 적절한 범위의 "참가 가능한"연결을 피할 것인지의 여부
brumScouse

1
동일한 트랜잭션 범위에서 중첩 된 연결은 분산 트랜잭션으로 승격됩니다. SQL Server 2008 이상에서 동일한 트랜잭션 범위에있는 여러 개의 중첩되지 않은 연결은 분산 트랜잭션으로 승격되지 않습니다.
PreguntonCojoneroCabrón

답변:


71

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

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

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


예, 세부 정보가 정확하며 실제로 코드를 보는 사람이 있습니까? 트랜잭션 범위에는 두 개의 연결이 있지만 한 번에 하나의 연결 만 인스턴스화되고 열립니다. 또한, DTC는 작동중인 컴퓨터에서 실행되고 있지 않습니다.
Yoopergeek 2009

1
"그러나 단 한 번에 하나의 연결 만 인스턴스화되고 열린 경우"-왜 관련이 있습니까? SQL2005를 사용하면 트랜잭션 범위 내에서 둘 이상의 연결을 열면 연결이 동시에 열려 있는지 여부가 에스컬레이션됩니다. 당신이 그것에 대해 생각하면 논리적입니다.
Joe

귀하와 Hwiechers는 이제 제게 두 번째 추측을 가지고 있으며 월요일에 일을 시작하고 개별 시스템을 더 자세히 검사하고 SQL Server 버전이 이전에보고 된대로 있는지 궁금합니다.
Yoopergeek 2009

19
당신과 허위가 옳습니다. 나는 얼굴 전체에 알이 있습니다. 단서로 날 때려 줘서 고마워 :) 당신이 처음 이었기 때문에 답을 얻습니다. SQL2008에서는 여러 연결을 열 수 있지만 동시에 할 수는 없지만 한 가지 명확한 설명을 추가하고 싶습니다. 주어진 시간에 하나의 연결 만 열려 있거나 TransactionScope가 DTC로 에스컬레이션됩니다.
Yoopergeek 2009

@Yoopergeek 나는 당신의 "동시가 아님"이 중요하고 @Joe의 대답에 따라 편집되었음을 확인할 수 있습니다. 테스트 중에 TCP 연결을 모니터링하면 연결을 동시에 사용하지 않으면 이전 TCP 연결이 재사용되므로 서버 측에서 TransactionScope단일 연결 COMMIT을 사용하면 에스컬레이션이 불필요 해집니다.
Eugene Beresovsky

58

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

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

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

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


1
연구를 공유해 주셔서 감사합니다. 정말 도움이되었습니다. 하나 더 빠른 쿼리. TransactionScope ()와 sqlConnection.BeginTransaction ()의 차이점은 무엇입니까?
Baig

기능 요청 에 따르면 ODAC 12C는 이제 동일한 데이터 소스에 대한 연속 연결을 사용할 때 분산으로 승격되지 않고 SQL 2008로 작동해야합니다.
Frédéric

31

이 코드 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가 실패하는 이유를 설명 할 수 없습니다. 그 반대의 방법이 아닙니까?


10

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

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

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

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



2

중첩 연결이 문제인지 확실하지 않습니다. 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();
        }
    }

어떤 SQL Server 버전을 사용하고 있습니까? 2008R2 및 / 또는 Denali의 변경 사항을 반영하여 @Peter Meinl의 답변을 업데이트해야하는지 궁금합니다.
Yoopergeek

SQL Server 2008 R2를 사용하고 있습니다.
Iftikhar Ali

2008 R2가 더 잘 작동하는지 궁금합니다. @ hwiechers 답변은 또한 컴파일하는 Framework 버전이 에스컬레이션을 방해하는지 궁금해합니다. 마지막으로 로컬 R2 인스턴스가 어떤 차이가 있는지 궁금합니다. 2008 R2 및 SQL Server 2012의 출시와 함께 어떻게 바뀌 었는지 조사 할 시간 / 자원이
있었으면 좋겠습니다

중첩 된 연결이 문제인지 확실하지 않습니까? lol ... 잘 피는 다음 그것을 제거하십시오!, 왜 지구상에서 사람들이 절대적으로 필요하지 않을 때 진술을 사용하여 둥지를 짓는 지, 나는 결코 알지 못할 것입니다.
Paul Zahra

1

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

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


0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.