Trong dự án của chúng tôi, chúng tôi đang sử dụng TransactionScope để đảm bảo lớp truy cập dữ liệu của chúng tôi thực hiện các hành động của nó trong một giao dịch. Chúng tôi đang hướng tới việc không yêu cầu dịch vụ MSDTC được kích hoạt trên các máy của người dùng cuối.
Rắc rối là, trên một nửa số máy phát triển của chúng tôi, chúng tôi có thể chạy với MSDTC bị vô hiệu hóa. Nửa còn lại phải kích hoạt hoặc họ nhận được thông báo lỗi "MSDTC trên [SERVER] không khả dụng" .
Nó thực sự khiến tôi phải vò đầu bứt tai và nghiêm túc cân nhắc việc quay trở lại với một giải pháp giống như Giao dịch tại nhà dựa trên các đối tượng giao dịch ADO.NET. Nó dường như điên - mã tương tự mà công trình (và không leo thang) trên một nửa số nhà phát triển của chúng tôi là làm leo thang vào nhà phát triển khác.
Tôi đã hy vọng có câu trả lời tốt hơn cho Trace tại sao một giao dịch được chuyển đến DTC nhưng thật không may là nó không hoạt động.
Đây là một đoạn mã mẫu sẽ gây ra sự cố, trên các máy cố gắng leo thang, nó cố gắng leo thang trên kết nối thứ hai. Mở () (và vâng, không có kết nối nào khác mở vào thời điểm đó.)
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();
}
Chúng tôi đã thực sự đào sâu và cố gắng tìm ra điều này. Dưới đây là một số thông tin về các máy mà nó hoạt động:
- Nhà phát triển 1: Windows 7 x64 SQL2008
- Nhà phát triển 2: Windows 7 x86 SQL2008
- Nhà phát triển 3: Windows 7 x64
SQL2005SQL2008
Các nhà phát triển không hoạt động trên:
- Nhà phát triển 4: Windows 7 x64,
SQL2008SQL2005 - Nhà phát triển 5: Windows Vista x86, SQL2005
- Nhà phát triển 6: Windows XP X86, SQL2005
- Máy tính gia đình của tôi: Windows Vista Home Premium, x86, SQL2005
Tôi nên nói thêm rằng tất cả các máy, trong nỗ lực tìm ra vấn đề, đã được vá đầy đủ mọi thứ có sẵn từ Microsoft Update.
Cập nhật 1:
- http://social.msdn.microsoft.com/forums/en-US/windowstransilitiesprogramming/thread/a5462509-8d6d-4828-aefa-a197456081d3/ mô tả một vấn đề tương tự ... vào năm 2006!
- http://msdn.microsoft.com/en-us/l Library / system.transilities.transilitiescope% 28VS.80% 29.aspx - đọc mẫu mã đó, nó thể hiện rõ kết nối được lồng vào nhau (đến máy chủ SQL thứ hai, thực tế) sẽ leo thang đến DTC. Chúng tôi không thực hiện điều này trong mã của mình - chúng tôi không sử dụng các máy chủ SQL khác nhau, cũng không phải các chuỗi kết nối khác nhau, chúng tôi cũng không mở các kết nối thứ cấp lồng nhau - không nên leo thang lên DTC .
- http://davidhayden.com/blog/dave/archive/2005/12/09/2615.aspx (từ 2005) nói về việc leo thang đến DTC sẽ luôn xảy ra khi kết nối với SQL2000. Chúng tôi đang sử dụng SQL2005 / 2008
- http://msdn.microsoft.com/en-us/l Library / ms229978.aspx MSDN khi leo thang giao dịch.
Trang leo thang giao dịch MSDN đó nói rằng các điều kiện sau đây sẽ khiến giao dịch leo thang lên DTC:
- Ít nhất một tài nguyên bền không hỗ trợ thông báo một pha được liệt kê trong giao dịch.
- Ít nhất hai tài nguyên bền có hỗ trợ thông báo một pha được liệt kê trong giao dịch. Ví dụ: tranh thủ một kết nối duy nhất không khiến giao dịch được quảng bá. Tuy nhiên, bất cứ khi nào bạn mở kết nối thứ hai đến cơ sở dữ liệu khiến cơ sở dữ liệu phải nhập ngũ, cơ sở hạ tầng System.Transilities sẽ phát hiện ra rằng đó là tài nguyên bền thứ hai trong giao dịch và chuyển nó thành giao dịch MSDTC.
- Yêu cầu "sắp xếp" giao dịch đến một miền ứng dụng khác hoặc quy trình khác được đưa ra. Ví dụ: việc tuần tự hóa đối tượng giao dịch qua một ranh giới miền ứng dụng. Đối tượng giao dịch được sắp xếp theo giá trị, có nghĩa là bất kỳ nỗ lực nào để vượt qua nó qua một ranh giới miền ứng dụng (ngay cả trong cùng một quy trình) đều dẫn đến việc tuần tự hóa đối tượng giao dịch. Bạn có thể vượt qua các đối tượng giao dịch bằng cách thực hiện cuộc gọi trên một phương thức từ xa lấy Giao dịch làm tham số hoặc bạn có thể thử truy cập vào một thành phần được phục vụ giao dịch từ xa. Điều này tuần tự hóa đối tượng giao dịch và dẫn đến sự leo thang, như khi một giao dịch được tuần tự hóa trên một miền ứng dụng. Nó đang được phân phối và người quản lý giao dịch địa phương không còn đủ.
Chúng tôi không trải nghiệm # 3. # 2 không xảy ra vì chỉ có một kết nối tại một thời điểm và đó cũng là một "tài nguyên bền vững" duy nhất. Có cách nào mà # 1 có thể xảy ra không? Một số cấu hình SQL2005 / 8 khiến nó không hỗ trợ thông báo một pha?
Cập nhật 2:
Điều tra lại, cá nhân, các phiên bản SQL Server của mọi người - "Dev 3" thực sự có SQL2008 và "Dev 4" thực sự là SQL2005. Điều đó sẽ dạy tôi không bao giờ tin tưởng đồng nghiệp của mình nữa. ;) Vì sự thay đổi dữ liệu này, tôi khá chắc chắn rằng chúng tôi đã tìm thấy vấn đề của mình. Các nhà phát triển SQL2008 của chúng tôi không gặp phải vấn đề này vì SQL2008 có số lượng lớn tuyệt vời bao gồm SQL2005 không có.
Nó cũng cho tôi biết rằng vì chúng tôi sẽ hỗ trợ SQL2005 nên chúng tôi không thể sử dụng TransactionScope như chúng tôi đã từng và nếu chúng tôi muốn sử dụng TransactionScope, chúng tôi sẽ cần phải truyền một đối tượng SqlConnection duy nhất xung quanh ... có vẻ như có vấn đề trong các tình huống mà SqlConnection không thể dễ dàng được thông qua ... nó chỉ có mùi của cá thể SqlConnection toàn cầu. Đáng tiếc!
Cập nhật 3
Chỉ cần làm rõ ở đây trong câu hỏi:
SQL2008:
- Cho phép nhiều kết nối trong một Giao dịch viên duy nhất (như được minh họa trong mã mẫu ở trên.)
- Hãy cẩn thận # 1: Nếu nhiều SqlConnections đó được lồng vào nhau, nghĩa là, hai hoặc nhiều SqlConnections được mở cùng một lúc, TransactionScope sẽ ngay lập tức leo lên DTC.
- Hãy cẩn thận # 2: Nếu một SqlConnection bổ sung được mở tới một 'tài nguyên bền vững' khác (nghĩa là: một máy chủ SQL khác), nó sẽ ngay lập tức leo lên DTC
SQL2005:
- Không cho phép nhiều kết nối trong một Giao dịch, một khoảng thời gian. Nó sẽ leo thang khi / nếu một SqlConnection thứ hai được mở.
Cập nhật 4
Vì lợi ích của làm cho câu hỏi này thậm chí nhiều hơn của một mớ hỗn độn hữu ích, và chỉ vì lợi ích hơn sự rõ ràng, đây là cách bạn có thể nhận được SQL2005 leo thang để DTC với một đơn SqlConnection
:
using (TransactionScope transactionScope = new TransactionScope()) {
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
connection.Close();
connection.Open(); // escalates to DTC
}
}
Điều này dường như bị phá vỡ đối với tôi, nhưng tôi đoán tôi có thể hiểu nếu mọi cuộc gọi đến SqlConnection.Open()
được lấy từ nhóm kết nối.
"Tại sao điều này có thể xảy ra, mặc dù?" Chà, nếu bạn sử dụng SqlTableAd CHƯƠNG theo kết nối đó trước khi mở, SqlTableAd CHƯƠNG sẽ mở và đóng kết nối, kết thúc giao dịch cho bạn một cách hiệu quả vì giờ bạn không thể mở lại.
Vì vậy, về cơ bản, để sử dụng thành công TransactionScope với SQL2005, bạn cần phải có một số loại đối tượng kết nối toàn cầu vẫn mở từ thời điểm của Giao dịch viên đầu tiên được khởi tạo cho đến khi không còn cần thiết nữa. Bên cạnh mùi mã của một đối tượng kết nối toàn cầu, việc mở kết nối trước và đóng lại lần cuối là mâu thuẫn với logic mở kết nối càng sớm càng tốt và đóng lại càng sớm càng tốt.