TransactionScope ส่งต่อไปยัง MSDTC ในเครื่องบางเครื่องโดยอัตโนมัติหรือไม่


284

ในโครงการของเราที่เรากำลังใช้ TransactionScope เพื่อให้แน่ใจว่าการเข้าถึงข้อมูลประสิทธิภาพชั้นของเราก็ดำเนินการในการทำธุรกรรม เรากำลังเล็งที่จะไม่จำเป็นต้องใช้บริการ MSDTC ที่จะเปิดใช้งานบนเครื่องของเรา end-user

ปัญหาคือในครึ่งหนึ่งของเครื่องนักพัฒนาของเราเราสามารถเรียกใช้โดยปิดการใช้งาน MSDTC อีกครึ่งหนึ่งต้องเปิดใช้งานหรือพวกเขาได้รับข้อความข้อผิดพลาด"MSDTC บน [เซิร์ฟเวอร์] ไม่พร้อมใช้งาน"

จริงๆมันมีฉันเกาหัวของฉันและฉันมีการพิจารณาอย่างจริงจังกลับไปกลิ้งบ้านปั่น TransactionScope เหมือนการแก้ปัญหาบนพื้นฐานของการทำธุรกรรมวัตถุ ADO.NET มันดูเหมือนว่าบ้า - รหัสเดียวกันที่ใช้งานได้ (และไม่เพิ่มขึ้น) ในครึ่งหนึ่งของผู้พัฒนาของเราไม่บานปลายบนผู้พัฒนารายอื่น

ฉันหวังว่าจะได้คำตอบที่ดีกว่าในการติดตามว่าเหตุใดธุรกรรมจึงถูกส่งต่อไปยัง 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();
}

เราได้ขุดและพยายามคิดออก นี่คือข้อมูลบางอย่างเกี่ยวกับเครื่องที่ทำงานบน:

  • Dev 1: Windows 7 x64 SQL2008
  • Dev 2: Windows 7 x86 SQL2008
  • Dev 3: Windows 7 x64 SQL2005 SQL2008

นักพัฒนาซอฟต์แวร์ไม่ทำงาน:

  • Dev 4: Windows 7 x64, SQL2008 SQL2005
  • Dev 5: Windows Vista x86, SQL2005
  • Dev 6: Windows XP X86, SQL2005
  • My Home PC: Windows Vista Home Premium, x86, SQL2005

ฉันควรเพิ่มว่าทุกเครื่องในความพยายามที่จะตามหาปัญหาได้รับการแก้ไขอย่างสมบูรณ์กับทุกสิ่งที่มีอยู่ใน Microsoft Update

Update 1:

หน้าการเพิ่มธุรกรรม MSDN ระบุว่าเงื่อนไขต่อไปนี้จะทำให้ธุรกรรมเพิ่มขึ้นเป็น DTC:

  1. ทรัพยากรคงทนอย่างน้อยหนึ่งรายการที่ไม่สนับสนุนการแจ้งเตือนแบบเฟสเดียวนั้นมีอยู่ในธุรกรรม
  2. ทรัพยากรคงทนอย่างน้อยสองแห่งที่สนับสนุนการแจ้งเตือนแบบเฟสเดียวมีเกณฑ์ในการทำธุรกรรม ตัวอย่างเช่นการลงทะเบียนการเชื่อมต่อเดียวด้วยจะไม่ทำให้เกิดการทำธุรกรรมที่จะได้รับการส่งเสริม อย่างไรก็ตามเมื่อใดก็ตามที่คุณเปิดการเชื่อมต่อที่สองไปยังฐานข้อมูลที่ทำให้ฐานข้อมูลเข้าสู่โครงสร้างพื้นฐาน System.Transactions ตรวจพบว่ามันเป็นทรัพยากรคงทนครั้งที่สองในการทำธุรกรรมและส่งต่อไปยังธุรกรรม MSDTC
  3. การร้องขอไปยัง "marshal" การทำธุรกรรมไปยังโดเมนแอปพลิเคชันอื่นหรือกระบวนการที่แตกต่างถูกเรียกใช้ ตัวอย่างเช่นการทำให้เป็นอันดับของวัตถุธุรกรรมข้ามขอบเขตโดเมนแอปพลิเคชัน วัตถุการทำธุรกรรมเป็น marshaled-by-value ซึ่งหมายความว่าความพยายามใด ๆ ที่จะส่งผ่านข้ามขอบเขตของโดเมนแอปพลิเคชัน (แม้ในกระบวนการเดียวกัน) ส่งผลให้เกิดการทำธุรกรรมวัตถุ คุณสามารถส่งผ่านวัตถุธุรกรรมได้โดยการเรียกใช้วิธีการระยะไกลที่รับธุรกรรมเป็นพารามิเตอร์หรือคุณสามารถลองเข้าถึงส่วนประกอบที่ให้บริการทำธุรกรรมระยะไกล นี้ serializes วัตถุการทำธุรกรรมและผลในการเพิ่มเช่นเมื่อมีการทำธุรกรรมต่อเนื่องทั่วทั้งโดเมนของแอพลิเคชัน มันจะถูกกระจายและการจัดการธุรกรรมท้องถิ่นจะไม่เพียงพอ

เราไม่พบ # 3 # 2 ไม่ได้เกิดขึ้นเพราะมีเพียงหนึ่งเคยเชื่อมต่อได้ตลอดเวลาและก็ยังเป็นหนึ่งเดียว 'ทรัพยากรคงทน' มีวิธีใด # # ที่อาจเกิดขึ้น? คอนฟิกูเรชัน SQL2005 / 8 บางตัวที่ทำให้ไม่รองรับการแจ้งเตือนแบบเฟสเดียว?

อัปเดต 2:

ตรวจสอบอีกครั้งโดยส่วนตัวแล้ว SQL Server ทุกเวอร์ชัน - "Dev 3" จริง ๆ แล้วมี SQL2008 และ "Dev 4" จริงๆแล้วคือ SQL2005 นั่นจะสอนให้ฉันไม่เชื่อใจเพื่อนร่วมงานอีกเลย ;) เนื่องจากการเปลี่ยนแปลงของข้อมูลนี้ฉันค่อนข้างแน่ใจว่าเราพบปัญหาของเราแล้ว นักพัฒนา SQL2008 ของเราไม่พบปัญหาเนื่องจาก SQL2008 มียอดเยี่ยมมากมายรวมถึง SQL2005 ที่ไม่มี

นอกจากนี้ยังบอกฉันว่าเพราะเราจะสนับสนุน SQL2005 ที่เราไม่สามารถใช้ TransactionScope เหมือนที่เราเคยเป็นและถ้าเราต้องการใช้ TransactionScope เราจะต้องผ่านวัตถุ SqlConnection เดียวรอบ ๆ ... ซึ่งดูเหมือนว่ามีปัญหาในสถานการณ์ที่ SqlConnection ไม่สามารถผ่านได้อย่างง่ายดาย ... มันเป็นเพียงแค่กลิ่นของอินสแตนซ์ของ SqlConnection ระดับโลก Pew!

อัปเดต 3

เพียงชี้แจงให้ชัดเจนที่นี่ในคำถาม:

SQL2008:

  • อนุญาตการเชื่อมต่อหลายรายการภายใน TransactionScope เดียว (ดังที่แสดงในตัวอย่างโค้ดด้านบน)
  • Caveat # 1: หาก SqlConnections หลายรายการซ้อนกันนั่นคือ SqlConnections สองรายการขึ้นไปถูกเปิดในเวลาเดียวกัน TransactionScope จะเพิ่มขึ้นเป็น DTC ทันที
  • Caveat # 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 จะเปิดและปิดการเชื่อมต่ออย่างมีประสิทธิภาพการทำธุรกรรมให้คุณเพราะตอนนี้คุณไม่สามารถเปิดมันอีกครั้ง

ดังนั้นโดยทั่วไปเพื่อที่จะประสบความสำเร็จในการใช้ TransactionScope กับ SQL2005 คุณจำเป็นต้องมีวัตถุการเชื่อมต่อระดับโลกบางอย่างที่ยังคงเปิดอยู่จากจุดแรกของ TransactionScope จนกระทั่งอินสแตนซ์นั้นไม่จำเป็นอีกต่อไป นอกจากกลิ่นรหัสของวัตถุการเชื่อมต่อทั่วโลกแล้วการเปิดการเชื่อมต่อก่อนและปิดสุดท้ายนั้นเป็นการขัดแย้งกับตรรกะของการเปิดการเชื่อมต่อให้ช้าที่สุดและปิดโดยเร็วที่สุด


คุณสามารถขยาย "ทำสิ่งอื่น ๆ ที่นี่ที่อาจมีหรือไม่มีส่วนร่วมในการทำธุรกรรมโดยรอบ" แน่นอนว่าสิ่งที่อยู่ในนั้นส่งผลกระทบอย่างมากต่อวิธีการทำงานของรหัส?
RichardOD

2
"# 2 ไม่ได้เกิดขึ้นเพราะมีเพียงหนึ่งเคยเชื่อมต่อได้ตลอดเวลา" - # 2 ไม่ได้บอกว่าความต้องการเชื่อมต่อที่สองที่จะเปิดในเวลาเดียวกันเพียงว่าจะต้องมีการสมัครเป็นทหารในรายการเดียวกัน
Joe

3
ขอบคุณมากสำหรับการรายงานกลับพร้อมอัปเดต 4 ที่แสดงว่าการยกระดับสามารถเกิดขึ้นได้ด้วย SqlConnection เพียงรายการเดียว ตรงนี้เป็นสิ่งที่ฉันทำงานแม้จะมีความมั่นใจว่ามีเพียง SqlConnection เดียวที่ใช้ เป็นเรื่องดีที่รู้ว่าเป็นคอมพิวเตอร์ที่บ้าและไม่ใช่ฉัน :-)
Oran Dennison

ในแง่ของการรวมการเชื่อมต่อถ้าเรามีหลายการเชื่อมต่อ (และซ้อนกันถ้าจำเป็น) ถ้าเรากำลังเปิดและปิดทีละครั้งเราจะใช้ทรัพยากรสระว่ายน้ำร่วมจริง 1 ตัวหรือ 1 ต่อการเชื่อมต่อฉันพยายามหาเหตุผลเข้าข้างตนเอง หรือไม่ที่จะมีการกำหนดขอบเขต conneection "enlistable" อย่างเหมาะสม (ซึ่งฉันต้องการหลีกเลี่ยง)
brumScouse

1
การเชื่อมต่อที่ซ้อนกันภายใต้ขอบเขตการทำธุรกรรมเดียวกันจะส่งเสริมการทำธุรกรรมแบบกระจาย จาก SQL Server 2008 และสูงกว่าการเชื่อมต่อหลาย ๆ (ไม่ใช่การซ้อน) ภายใต้ขอบเขตการทำธุรกรรมเดียวกันจะไม่เลื่อนระดับเป็น Transaciton แบบกระจาย
PreguntonCojoneroCabrón

คำตอบ:


71

SQL Server 2008 สามารถใช้หลายSQLConnections ในหนึ่งเดียวTransactionScopeโดยไม่ต้องเลื่อนระดับหากการเชื่อมต่อไม่เปิดในเวลาเดียวกันซึ่งจะส่งผลให้เกิดการเชื่อมต่อ TCP "จริง" หลายครั้งดังนั้นจึงจำเป็นต้องมีการเลื่อนระดับ

ฉันเห็นนักพัฒนาของคุณบางคนมี SQL Server 2005 และคนอื่น ๆ มี SQL Server 2008 คุณแน่ใจหรือไม่ว่าคุณได้ระบุอย่างถูกต้องว่าตัวใดกำลังเพิ่มและไม่

คำอธิบายที่ชัดเจนที่สุดคือนักพัฒนาที่มี SQL Server 2008 เป็นคำที่ไม่ได้เพิ่มขึ้น


ใช่รายละเอียดถูกต้องและมีใครดูรหัสจริงหรือไม่ มีการเชื่อมต่อสองรายการภายในขอบเขตการทำธุรกรรมอย่างไรก็ตามมีการเชื่อมต่อเพียงครั้งเดียวเท่านั้นที่เปิดใช้และเปิดขึ้นพร้อมกันในช่วงเวลาเดียว นอกจากนี้ไม่ DTC ไม่ทำงานบนเครื่องที่ใช้งานได้
Yoopergeek

1
"อย่างไรก็ตามมีการเชื่อมต่อเพียงครั้งเดียวที่สร้างและเปิดในเวลาเดียว" - ทำไมจึงมีความเกี่ยวข้อง ด้วย SQL2005 หากคุณเปิดการเชื่อมต่อมากกว่าหนึ่งรายการภายในขอบเขตการทำธุรกรรมคุณจะเพิ่มระดับว่าจะยังคงเปิดพร้อมกันหรือไม่ ซึ่งเป็นตรรกะถ้าคุณคิดเกี่ยวกับมัน
Joe

ตอนนี้คุณและเหล่า hwiechers คาดเดาฉันเป็นครั้งที่สองและฉันอยากทำงานวันจันทร์และตรวจสอบเครื่องจักรแต่ละเครื่องอย่างใกล้ชิดยิ่งขึ้นและตรวจสอบให้แน่ใจว่าเวอร์ชันของ SQL Server เป็นไปตามที่รายงานไว้ก่อนหน้านี้
Yoopergeek

19
คุณและ hwiechers พูดถูก ฉันมีไข่ทั่วใบหน้า ขอบคุณสำหรับการตีฉันด้วยเบาะแส :) เพราะคุณเป็นคนแรกคุณจะได้คำตอบ ฉันต้องการเพิ่มจุดหนึ่งของการชี้แจงแม้ว่า - SQL2008 อนุญาตให้เปิดการเชื่อมต่อหลายรายการ แต่ไม่ใช่ในเวลาเดียวกัน ยังคงมีเพียงการเชื่อมต่อเดียวที่เปิดในเวลาใดก็ตามหรือ TransactionScope จะเลื่อนไปยัง DTC
Yoopergeek

@Yoopergeek ฉันสามารถตรวจสอบว่า "ไม่ได้ในเวลาเดียวกัน" ของคุณเป็นสิ่งสำคัญและแก้ไข @Joe 's คำตอบตาม การตรวจสอบการเชื่อมต่อ TCP ในขณะที่การทดสอบแสดงให้เห็นว่าการเชื่อมต่อ TCP แบบเก่าจะถูกนำมาใช้ซ้ำเมื่อการเชื่อมต่อไม่ได้ถูกใช้ในเวลาเดียวกันและTransactionScopeสามารถทำได้ด้วยการเชื่อมต่อแบบเดี่ยวCOMMITทางฝั่งเซิร์ฟเวอร์ซึ่งจะทำให้การเพิ่มระดับฟุ่มเฟือย
Eugene Beresovsky

58

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

ในเวอร์ชัน 2.0 ของ. NET Framework และ SQL Server 2005 การเปิดการเชื่อมต่อครั้งที่สองภายใน TransactionScope จะส่งเสริมธุรกรรมเป็นธุรกรรมการกระจายแบบเต็มโดยอัตโนมัติแม้ว่าการเชื่อมต่อทั้งคู่ใช้สตริงการเชื่อมต่อที่เหมือนกัน ในกรณีนี้ธุรกรรมแบบกระจายจะเพิ่มค่าใช้จ่ายที่ไม่จำเป็นซึ่งลดประสิทธิภาพลง

เริ่มต้นด้วย SQL Server 2008 และรุ่น 3.5 ของ. NET Framework ธุรกรรมในเครื่องจะไม่เลื่อนระดับเป็นธุรกรรมแบบกระจายอีกต่อไปหากเปิดการเชื่อมต่ออื่นในธุรกรรมหลังจากปิดธุรกรรมก่อนหน้า สิ่งนี้ไม่จำเป็นต้องมีการเปลี่ยนแปลงรหัสของคุณหากคุณใช้การรวมการเชื่อมต่อและเกณฑ์ในการทำธุรกรรม

ฉันไม่สามารถอธิบายได้ว่าทำไม Dev 3: Windows 7 x64, SQL2005 ประสบความสำเร็จและ Dev 4: Windows 7 x64 ล้มเหลว คุณแน่ใจหรือว่าไม่ใช่วิธีอื่น


10

ฉันไม่รู้ว่าทำไมคำตอบนี้ถูกลบ แต่ดูเหมือนว่าจะมีข้อมูลที่เกี่ยวข้อง

ตอบ 4 ส.ค. 2010 เวลา 17:42 Eduardo

  1. ตั้งค่าEnlist = falseบนสตริงการเชื่อมต่อเพื่อหลีกเลี่ยงการเข้าร่วมอัตโนมัติในการทำธุรกรรม

  2. เกณฑ์การเชื่อมต่อด้วยตนเองเป็นผู้เข้าร่วมในขอบเขตการทำธุรกรรม [ บทความต้นฉบับล้าสมัย] หรือทำสิ่งนี้: วิธีป้องกันการเลื่อนระดับ MSDTC อัตโนมัติ [ไฟล์เก็บถาวรนี้]


msdn.microsoft.com/en-us/library/ms172153%28v=VS.80%29.aspxไม่พบ, Visual Studio 2005 เอกสารประกอบ Retired
Kiquenet

2

ฉันไม่แน่ใจเหมือนกันว่าการเชื่อมต่อแบบซ้อนเป็นปัญหาหรือไม่ ฉันกำลังเรียกอินสแตนซ์ในเครื่องของเซิร์ฟเวอร์ SQL และไม่สร้าง 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 รุ่นใดที่คุณใช้อยู่ ฉันสงสัยว่าคำตอบของ @Peter Meinl จำเป็นต้องได้รับการอัปเดตเพื่อแสดงถึงการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นในปี 2008R2 และ / หรือ Denali
Yoopergeek

ฉันใช้ SQL Server 2008 R2
Iftikhar Ali

ฉันสงสัยว่า 2008 R2 นั้นมีพฤติกรรมที่ดีขึ้นหรือไม่ @hwiechers คำตอบยังทำให้ฉันสงสัยว่าเวอร์ชันของ Framework ที่คุณกำลังคอมไพล์ต่อต้านการเพิ่มระดับ ในที่สุดฉันสงสัยว่ามันเป็นอินสแตนซ์ของ R2 ในท้องถิ่นที่สร้างความแตกต่างหรือไม่ ฉันหวังว่าฉันจะมีเวลา / ทรัพยากรเพื่อตรวจสอบว่าสิ่งนี้เปลี่ยนแปลงไปอย่างไรกับการเปิดตัว 2008 R2 และ SQL Server 2012
Yoopergeek

ไม่แน่ใจว่าปัญหาการเชื่อมต่อซ้อนอยู่หรือไม่ ฮ่า ๆ ... เบ่งบานเอามันออกแล้ว! ทำไมผู้คนถึงทำรังโดยใช้คำแถลงเมื่อไม่จำเป็นจริงๆฉันจะไม่มีทางรู้
พอล Zahra

1

TransactionScope จะเพิ่มระดับให้กับธุรกรรม DTC เสมอหากคุณใช้การเข้าถึงมากกว่า 1 การเชื่อมต่อภายใน วิธีเดียวที่รหัสข้างต้นสามารถทำงานกับ DTC ที่ถูกปิดการใช้งานคือหากมีโอกาสมากที่คุณจะได้รับการเชื่อมต่อเดียวกันจากพูลการเชื่อมต่อทั้งสองครั้ง

"ปัญหาคือในครึ่งหนึ่งของเครื่องนักพัฒนาของเราเราสามารถเรียกใช้โดยปิดการใช้งาน MSDTC" แน่ใจหรือไม่ว่ามันถูกปิดใช้งาน;)


0

ตรวจสอบให้แน่ใจว่า connectionString ของคุณไม่ได้ตั้งค่าการรวมเป็นเท็จ สิ่งนี้จะส่งผลให้เกิดการเชื่อมต่อใหม่สำหรับแต่ละ SqlConnection ใหม่ใน TransactionScope และส่งต่อไปยัง DTC

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.