Projemizde, veri erişim katmanımızın işlemlerini bir işlemde gerçekleştirmesini sağlamak için TransactionScope'u kullanıyoruz. Biz amaçlıyoruz değil bizim son kullanıcının makinelerde etkin olmasını MSDTC hizmetini gerektirir.
Sorun, geliştirici makinelerimizin yarısında MSDTC devre dışı bırakıldığında çalışabiliriz. Diğer yarısı etkinleştirilmiş olmalı veya "[SUNUCU] üzerinde MSDTC kullanılamıyor" hata iletisini alır.
Gerçekten kafamı kaşıyor ve cidden ADO.NET işlem nesnelerine dayalı evde bükülmüş bir TransactionScope benzeri bir çözüme geri dönmeyi düşünüyor. Bu görünüşte deli - Aynı işleri (ve kızıştırmak değil) bu kod bizim geliştirici yarısıdır üzerinde yaptığı diğer geliştirici en üstünde tırmandırmaya.
Bir işlemin neden DTC'ye yükseltildiğini takip etmek için daha iyi bir cevap bekliyordum ama maalesef öyle değil.
Soruna neden olacak örnek bir kod parçası, tırmanmaya çalışan makinelerde, ikinci bağlantıda artmaya çalışıyor.Open () (ve evet, o sırada açık başka bir bağlantı yok.)
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();
}
Bunu gerçekten araştırdık ve anlamaya çalıştık. İşte üzerinde çalıştığı makineler hakkında bazı bilgiler:
- Dev 1: Windows 7 x64 SQL2008
- Dev 2: Windows 7 x86 SQL2008
- Dev 3: Windows 7 x64
SQL2005SQL2008
Üzerinde çalışmayan geliştiriciler:
- Dev 4: Windows 7 x64,
SQL2008SQL2005 - Dev 5: Windows Vista x86, SQL2005
- Dev 6: Windows XP X86, SQL2005
- Ev Bilgisayarım: Windows Vista Home Premium, x86, SQL2005
Sorunu avlamak için tüm makinelerin Microsoft Update'te bulunan her şeyle tamamen yamalanmış olduğunu eklemeliyim.
Güncelleme 1:
- http://social.msdn.microsoft.com/forums/en-US/windowstransactionsprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/ benzer bir sorunu anlatıyor ... 2006'da!
- http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28VS.80%29.aspx - bu kod örneğini okuyun, iç içe ikinci bir bağlantı gösterir (ikinci bir SQL sunucusuna, aslında) DTC'ye yükselir. Kodumuzda bunu yapmıyoruz - farklı SQL sunucuları veya farklı bağlantı dizeleri kullanmıyoruz, ayrıca ikincil bağlantıların açılışını da yapmıyoruz - DTC'ye yükseltilmemelidir .
- http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx (2005'ten itibaren), SQL2000'e bağlanırken DTC'ye yükselmenin her zaman nasıl olacağını anlatıyor. SQL2005 / 2008 kullanıyoruz
- http://msdn.microsoft.com/tr-tr/library/ms229978.aspx İşlem yükseltme konusunda MSDN.
MSDN işlem yükseltme sayfası, aşağıdaki koşulların bir işlemin DTC'ye yükseltilmesine neden olacağını belirtir:
- Tek fazlı bildirimleri desteklemeyen en az bir kalıcı kaynak işleme dahil edilir.
- Tek fazlı bildirimleri destekleyen en az iki kalıcı kaynak işleme dahil edilir. Örneğin, ile tek bir bağlantının bağlanması işlemin ilerletilmesine neden olmaz. Ancak, veritabanına kaydolmasına neden olan ikinci bir veritabanını açtığınızda, System.Transactions altyapısı, işlemdeki ikinci kalıcı kaynak olduğunu algılar ve bir MSDTC işlemine yükseltir.
- İşlemi farklı bir uygulama etki alanına veya farklı bir işleme "marshal" yapma isteği çağrılır. Örneğin, işlem nesnesinin bir uygulama etki alanı sınırı boyunca serileştirilmesi. İşlem nesnesi, değere göre sıralanır; başka bir deyişle, bir uygulama etki alanı sınırı boyunca (aynı işlemde bile) geçirme girişimi, işlem nesnesinin serileştirilmesine neden olur. İşlemi parametre olarak alan uzak bir yöntemle arama yaparak işlem nesnelerini iletebilir veya uzak işlem hizmetli bir bileşene erişmeyi deneyebilirsiniz. Bu işlem nesnesini serileştirir ve bir işlem bir uygulama etki alanında serileştirildiğinde olduğu gibi bir yükselmeye neden olur. Dağıtılıyor ve yerel işlem yöneticisi artık yeterli değil.
# 3 yaşamıyoruz. # 2 gerçekleşmiyor çünkü bir seferde sadece bir bağlantı var ve aynı zamanda tek bir 'dayanıklı kaynak'. # 1'in olmasının herhangi bir yolu var mı? Tek fazlı bildirimleri desteklememesine neden olan bazı SQL2005 / 8 yapılandırmaları?
Güncelleme 2:
Kişisel olarak herkesin SQL Server sürümleri yeniden araştırıldı - "Dev 3" aslında SQL2008'e sahip ve "Dev 4" aslında SQL2005. Bu bana bir daha asla iş arkadaşlarıma güvenmemeyi öğretecek. ;) Verilerdeki bu değişiklik nedeniyle, sorunumuzu bulduğumuzdan eminim. SQL2008 geliştiricilerimiz sorunu yaşamıyordu çünkü SQL2008, SQL2005'in sahip olmadığı çok sayıda harika.
Ayrıca SQL2005'i destekleyeceğimiz için TransactionScope'u bizim gibi kullanamayacağımızı ve TransactionScope'u kullanmak istiyorsak etrafta tek bir SqlConnection nesnesi geçirmemiz gerektiğini söylüyor ... SqlConnection'ın kolayca aktarılamadığı durumlarda sorunlu görünüyor ... sadece global-SqlConnection örneğinin kokuyor. Pew!
Güncelleme 3
Sadece burada soruya açıklık getirmek için:
SQL2008:
- Tek bir TransactionScope içinde birden fazla bağlantıya izin verir (yukarıdaki örnek kodda gösterildiği gibi).
- Uyarı # 1: Bu çoklu SqlConnections yuvalanmışsa, yani aynı anda iki veya daha fazla SqlConnections açılırsa, TransactionScope hemen DTC'ye yükselir.
- Uyarı # 2: Farklı bir 'dayanıklı kaynağa' (yani: farklı bir SQL Server'a) ek bir SqlConnection açılırsa , hemen DTC'ye yükselir
SQL2005:
- Tek bir TransactionScope, nokta içinde birden fazla bağlantıya izin vermez. İkinci bir SqlConnection açıldığında / açıldığında artar.
Güncelleme 4
Bu soruyu daha da karmaşık bir hale getirmek ve sadece daha fazla netlik uğruna, SQL2005'in DTC'ye tek bir adımla yükselmesini sağlayabilirsiniz SqlConnection
:
using (TransactionScope transactionScope = new TransactionScope()) {
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
connection.Close();
connection.Open(); // escalates to DTC
}
}
Bu sadece bana kırık gibi görünüyor, ama her çağrı SqlConnection.Open()
bağlantı havuzundan kapma olup olmadığını anlayabiliyorum sanırım .
"Peki bu neden olabilir?" Peki, açılmadan önce bu bağlantıya karşı bir SqlTableAdapter kullanırsanız, SqlTableAdapter bağlantıyı açar ve kapatır, işlem artık sizin için etkin bir şekilde tamamlanır, çünkü şimdi yeniden açamazsınız.
Bu nedenle, temel olarak, TransactionScope'u SQL2005 ile başarılı bir şekilde kullanmak için, ilk TransactionScope'un noktasından itibaren artık açık olana kadar açık kalan bir tür global bağlantı nesnesine sahip olmanız gerekir. Global bir bağlantı nesnesinin kod kokusunun yanı sıra, önce bağlantıyı açmak ve son olarak kapatmak, bir bağlantıyı mümkün olan en kısa sürede açma ve mümkün olan en kısa sürede kapatma mantığına aykırıdır.