TransactionScope bazı makinelerde otomatik olarak MSDTC'ye yükseliyor mu?


284

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 SQL2005 SQL2008

Üzerinde çalışmayan geliştiriciler:

  • Dev 4: Windows 7 x64, SQL2008 SQL2005
  • 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:

MSDN işlem yükseltme sayfası, aşağıdaki koşulların bir işlemin DTC'ye yükseltilmesine neden olacağını belirtir:

  1. Tek fazlı bildirimleri desteklemeyen en az bir kalıcı kaynak işleme dahil edilir.
  2. 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.
  3. İş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.


"Ortam işlemine dahil olabilecek veya olmayabilecek başka şeyler yapın" ı genişletebilir misiniz? Şüphesiz orada ne var kodun davranışını büyük ölçüde etkiler?
RichardOD

2
"# 2 gerçekleşmiyor çünkü bir seferde yalnızca bir bağlantı var" - # 2 ikinci bağlantının aynı anda açık olması gerektiğini söylemiyor, sadece aynı işleme dahil edilmesi gerekiyor.
Joe

3
Yalnızca tek bir SqlConnection ile güncellemenin nasıl gerçekleşebileceğini gösteren Güncelleme 4 ile geri bildirim yaptığınız için çok teşekkür ederiz. Sadece tek bir SqlConnection kullanılmasına dikkat etsem de tam olarak bu durumla karşılaşıyordum. Benim değil çılgın bilgisayar olduğunu bilmek güzel. :-)
Oran Dennison

Bağlantı havuzu oluşturma açısından, birden fazla bağlantımız varsa (ve gerekirse iç içe geçmişse), her seferinde bir tane açıp kapatacaksak, 1 gerçek bağlantı havuzu kaynağı veya bağlantı başına 1 kullanıyorsak, bunu belirlemek için bunu rasyonelleştirmeye çalışıyorum. (kaçınmak istiyorum) uygun şekilde "canlandırılabilir" konneksiyon kapsamına sahip olup olmadığı
brumScouse

1
Aynı işlem kapsamındaki yuvalanmış bağlantılar dağıtılmış bir işlemi destekleyecektir. SQL server 2008 ve üzeri sürümlerde aynı işlem kapsamı altındaki birden çok (iç içe geçmeyen) bağlantı dağıtılmış bir işlem için yükseltilmez.
PreguntonCojoneroCabrón

Yanıtlar:


71

SQL Server 2008 birden kullanabilirsiniz SQLConnectionbirinde s TransactionScopebirden çok "fiziksel" TCP bağlantıları ile sonuçlanabilir ve böylece artmasını gerektirecek bağlantıları aynı anda açık olmaması şartıyla tırmanan olmadan.

Bazı geliştiricilerinizde SQL Server 2005, bazılarında SQL Server 2008 bulunduğunu görüyorum.

En açık açıklama, SQL Server 2008'e sahip geliştiricilerin tırmanmayan olanlardır.


Evet, ayrıntılar doğru ve kodlara bakan var mı? İşlem kapsamında iki bağlantı vardır, ancak tek bir anda örneklenen ve açılan tek bir bağlantı vardır. Ayrıca, hayır, DTC çalışan makinelerde çalışmıyor.
Yoopergeek

1
"ancak, tek bir anda anlık olarak açılan ve açılan tek bir bağlantı vardır" - bu neden önemlidir? SQL2005 ile, bir işlem kapsamında birden fazla bağlantı açarsanız, eşzamanlı olarak açık kalıp kalmayacaklarını artıracaksınız. Bunu düşünürseniz mantıklı.
Joe

Sen ve hwiechers şimdi ikinci tahmin var ve Pazartesi işe başlamak ve bireysel makineleri daha yakından incelemek ve SQL Server sürümlerinin daha önce bildirildiği gibi emin olmak için endişeli.
Yoopergeek

19
Sen ve hwiechers haklısın. Yüzümün her yerinde yumurta var. Bana ipucu ile vurduğun için teşekkürler. :) Çünkü sen ilktin, cevabı aldın. Yine de bir noktaya açıklık eklemek istiyorum - SQL2008 aynı anda birden fazla bağlantının açılmasına izin veriyor. Herhangi bir zamanda hala tek bir bağlantı açık olabilir veya TransactionScope DTC'ye yükselir.
Yoopergeek

@Yoopergeek "Aynı anda değil" inizin önemli olduğunu ve @Joe'nin cevabını buna göre düzenlediğini doğrulayabilirim. Sınama sırasında TCP bağlantılarının izlenmesi, bağlantılar aynı anda kullanılmadığında eski TCP bağlantısının yeniden kullanılacağını ve bu nedenle sunucu tarafında TransactionScopetek bir COMMITadımla bunu yapabileceğini ve bu da tırmanmayı gereksiz hale getireceğini göstermiştir.
Eugene Beresovsky

58

Konuyla ilgili araştırmamın sonucu:

resim açıklamasını buraya girin

Bkz . Dağıtılmış İşlemlere İstenmeyen Eskalasyondan Kaçının

Hala Oracle'ın tırmanma davranışı araştırıyorum: Aynı DB birden çok bağlantı kapsayan işlemler DTC yükseliyor mu?


1
Araştırmanızı paylaştığınız için teşekkür ederiz. Gerçekten yardımcı oldu. Bir hızlı sorgu daha. TransactionScope () ve sqlConnection.BeginTransaction () arasındaki fark nedir?
Baig

Bu özellik isteğine göre , ODAC 12C artık SQL 2008 gibi davranmalı, aynı veri kaynağına ardışık bağlantılar kullanılırken dağıtılmayı desteklememelidir.
Frédéric

31

Bu kod , 2005'e bağlanırken bir artışa neden olacaktır .

MSDN'deki belgelere bakın - http://msdn.microsoft.com/en-us/library/ms172070.aspx

SQL Server 2008'de Promosyonlu İşlemler

.NET Framework ve SQL Server 2005'in 2.0 sürümünde, her iki bağlantıda da aynı bağlantı dizeleri kullanıyor olsa bile, bir TransactionScope içinde ikinci bir bağlantı açılması işlemi otomatik olarak tam dağıtılmış işleme yükseltecektir. Bu durumda, dağıtılmış bir işlem, performansı düşüren gereksiz ek yük ekler.

SQL Server 2008 ve .NET Framework 3.5 sürümünden başlayarak, önceki işlem kapatıldıktan sonra işlemde başka bir bağlantı açılırsa yerel işlemler artık dağıtılmış işlemlere yükseltilmez. Bağlantı havuzu oluşturmayı ve işlemlere kaydolmayı zaten kullanıyorsanız, kodunuzda herhangi bir değişiklik yapılmasını gerektirmez.

Dev 3: Windows 7 x64, SQL2005'in başarılı olduğunu ve Dev 4: Windows 7 x64'ün neden başarısız olduğunu açıklayamıyorum. Bunun tam tersi olmadığından emin misin?


10

Bu cevabın neden silindiğini bilmiyorum, ancak bunun bazı alakalı bilgiler var gibi görünüyor.

yanıtladı 4 '10 saat 17:42 Eduardo

  1. İşlemde otomatik kayıt yapılmasını önlemek için Enlist = bağlantı dizesinde false değerini ayarlayın .

  2. İşlem kapsamına manuel olarak bağlantıyı katılımcı olarak kaydedin . [ orijinal makale eski] veya bunu yapın: Otomatik MSDTC tanıtımı nasıl engellenir [archive.is]


msdn.microsoft.com/en-us/library/ms172153%28v=VS.80%29.aspx bulunamadı, Visual Studio 2005 Emekli belgeler
Kiquenet

2

İç içe bağlantının sorun olup olmadığından emin değilim. SQL sunucusunun yerel bir örneğini arıyorum ve DTC oluşturmuyor ??

    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();
        }
    }

Hangi SQL Server sürümünü kullanıyorsunuz? @Peter Meinl'in cevabının 2008R2 ve / veya Denali'de yapılan değişiklikleri yansıtacak şekilde güncellenmesi gerekip gerekmediğini merak ediyorum.
Yoopergeek

SQL Server 2008 R2 kullanıyorum.
Iftikhar Ali

2008 R2'nin daha iyi davranıp davranmadığını merak ediyorum? @hwiechers yanıtı, derlediğiniz Çerçevenin sürümünün tırmanmayı önleyip önlemediğini merak ediyor. Son olarak, yerel bir R2 örneği olmanın herhangi bir fark yaratıp yaratmadığını merak ediyorum. Keşke bunun 2008 R2 ve SQL Server 2012'nin piyasaya sürülmesiyle nasıl değiştiğini araştıracak zamanım / kaynaklara sahip
olsaydım

İç içe bağlantının sorun olup olmadığından emin değil misiniz? lol ... iyi çiçeklenme o zaman kaldırmak !, neden dünyada insanlar kesinlikle gerekli olmadığında ifadeleri kullanarak yuva yapmak, asla bilemeyeceğim.
Paul Zahra

1

TransactionScope, içinde 1'den fazla bağlantı kullanıyorsanız, her zaman DTC işlemine yükselir. Yukarıdaki kodun DTC devre dışı bırakılmışken çalışabilmesinin tek yolu, büyük olasılıkla bağlantı havuzundan iki kez aynı bağlantıyı elde etmenizdir.

"Sorun, geliştirici makinelerimizin yarısında MSDTC devre dışı bırakıldığında çalışabiliriz." Devre dışı olduğundan emin misiniz;)


0

ConnectionString öğenizin havuzlamayı false olarak ayarlamadığından emin olun. Bu, TransactionScope'taki her yeni SqlConnection için yeni bir bağlantıya neden olur ve bunu DTC'ye yükseltir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.