우리 프로젝트에서는 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
SQL2005SQL2008
작동하지 않는 개발자 :
- 개발자 4 : Windows 7 x64,
SQL2008SQL2005 - 개발자 5 : Windows Vista x86, SQL2005
- 개발자 6 : Windows XP X86, SQL2005
- 내 홈 PC : Windows Vista Home Premium, x86, SQL2005
문제를 해결하기 위해 모든 컴퓨터에 Microsoft Update에서 제공하는 모든 항목이 완전히 패치되었다고 덧붙여 야합니다.
업데이트 1 :
- http://social.msdn.microsoft.com/forums/en-US/windowstransactionsprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/ 은 비슷한 문제를 설명합니다.
- http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28VS.80%29.aspx- 해당 코드 샘플을 읽고 두 번째 SQL Server에 대한 중첩 초 연결을 명확하게 보여줍니다. 실제로) DTC로 이관합니다. 우리는 코드 에서이 작업을 수행하지 않습니다 -다른 SQL 서버 또는 다른 연결 문자열을 사용하지 않으며 중첩 된 보조 연결을 열지 않습니다-DTC로 에스컬레이션해서는 안됩니다 .
- http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx(2005 년)는 SQL2000에 연결할 때 DTC 로의 에스컬레이션이 항상 발생하는 방법에 대해 설명합니다. 우리는 SQL2005 / 2008을 사용하고 있습니다
- 트랜잭션 에스컬레이션에 대한 http://msdn.microsoft.com/en-us/library/ms229978.aspx MSDN
해당 MSDN 거래 에스컬레이션 페이지에 다음 조건으로 인해 거래가 DTC로 에스컬레이션 될 수 있음이 명시되어 있습니다.
- 단일 단계 알림을 지원하지 않는 하나 이상의 영구 리소스가 트랜잭션에 참여합니다.
- 단일 단계 알림을 지원하는 둘 이상의 영구 리소스가 트랜잭션에 참여합니다. 예를 들어, 단일 연결에 참여한다고해서 트랜잭션이 승격되지는 않습니다. 그러나 데이터베이스에 대한 두 번째 연결을 열면 데이터베이스가 참여하게됩니다. System.Transactions 인프라는 트랜잭션에서 두 번째 지속 가능한 리소스임을 감지하고이를 MSDTC 트랜잭션으로 에스컬레이션합니다.
- 트랜잭션을 다른 응용 프로그램 도메인이나 다른 프로세스에 "마샬링"하는 요청이 호출됩니다. 예를 들어, 응용 프로그램 도메인 경계를 가로 지르는 트랜잭션 개체의 직렬화입니다. 트랜잭션 객체는 값에 따라 마샬링됩니다. 즉, 동일한 프로세스에서도 응용 프로그램 도메인 경계를 통과하려고하면 트랜잭션 객체가 직렬화됩니다. 트랜잭션을 매개 변수로 사용하는 원격 메소드를 호출하여 트랜잭션 오브젝트를 전달하거나 원격 트랜잭션 서비스 구성 요소에 액세스 할 수 있습니다. 이렇게하면 트랜잭션이 응용 프로그램 도메인에서 직렬화 될 때처럼 트랜잭션 개체가 직렬화되고 에스컬레이션됩니다. 분배 중이며 로컬 트랜잭션 관리자가 더 이상 적합하지 않습니다.
# 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가 더 이상 필요하지 않을 때까지 인스턴스화되는 시점부터 열려있는 일종의 전역 연결 개체가 있어야합니다. 전역 연결 개체의 코드 냄새 외에도 연결을 먼저 열고 마지막으로 닫는 것은 가능한 한 늦게 연결을 열고 최대한 빨리 닫는 논리와 상충됩니다.