ในโครงการของเราที่เรากำลังใช้ 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
SQL2005SQL2008
นักพัฒนาซอฟต์แวร์ไม่ทำงาน:
- Dev 4: Windows 7 x64,
SQL2008SQL2005 - 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:
- http://social.msdn.microsoft.com/forums/en-US/windowstransactionsprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/อธิบายปัญหาที่คล้ายกัน ... กลับไปในปี 2006!
- http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28VS.80%29.aspx - อ่านตัวอย่างโค้ดนั้นแสดงให้เห็นถึงการเชื่อมต่อที่ซ้อนกันที่สอง (ไปยังเซิร์ฟเวอร์ SQL ตัวที่สอง จริง) ซึ่งจะเพิ่มเป็น DTC เราจะไม่ทำเช่นนี้ในรหัสของเรา - เราไม่ได้ใช้เซิร์ฟเวอร์ SQL ที่แตกต่างกันหรือสตริงการเชื่อมต่อที่แตกต่างกันเราไม่ได้มีการเชื่อมต่อรองที่ซ้อนกันเปิด - ไม่ควรมีการเพิ่มการ DTC
- http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx (ตั้งแต่ปี 2005) พูดถึงการเพิ่มขึ้นของ DTC จะเกิดขึ้นได้อย่างไรเมื่อเชื่อมต่อกับ SQL2000 เรากำลังใช้ SQL2005 / 2008
- http://msdn.microsoft.com/en-us/library/ms229978.aspx MSDN ในการเพิ่มการทำธุรกรรม
หน้าการเพิ่มธุรกรรม MSDN ระบุว่าเงื่อนไขต่อไปนี้จะทำให้ธุรกรรมเพิ่มขึ้นเป็น DTC:
- ทรัพยากรคงทนอย่างน้อยหนึ่งรายการที่ไม่สนับสนุนการแจ้งเตือนแบบเฟสเดียวนั้นมีอยู่ในธุรกรรม
- ทรัพยากรคงทนอย่างน้อยสองแห่งที่สนับสนุนการแจ้งเตือนแบบเฟสเดียวมีเกณฑ์ในการทำธุรกรรม ตัวอย่างเช่นการลงทะเบียนการเชื่อมต่อเดียวด้วยจะไม่ทำให้เกิดการทำธุรกรรมที่จะได้รับการส่งเสริม อย่างไรก็ตามเมื่อใดก็ตามที่คุณเปิดการเชื่อมต่อที่สองไปยังฐานข้อมูลที่ทำให้ฐานข้อมูลเข้าสู่โครงสร้างพื้นฐาน System.Transactions ตรวจพบว่ามันเป็นทรัพยากรคงทนครั้งที่สองในการทำธุรกรรมและส่งต่อไปยังธุรกรรม MSDTC
- การร้องขอไปยัง "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 จนกระทั่งอินสแตนซ์นั้นไม่จำเป็นอีกต่อไป นอกจากกลิ่นรหัสของวัตถุการเชื่อมต่อทั่วโลกแล้วการเปิดการเชื่อมต่อก่อนและปิดสุดท้ายนั้นเป็นการขัดแย้งกับตรรกะของการเปิดการเชื่อมต่อให้ช้าที่สุดและปิดโดยเร็วที่สุด