TransactionScope tự động leo thang lên MSDTC trên một số máy?


284

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

Các nhà phát triển không hoạt động trên:

  • Nhà phát triển 4: Windows 7 x64, SQL2008 SQL2005
  • 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:

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:

  1. Í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.
  2. Í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.
  3. 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.


Bạn có thể mở rộng "Làm những thứ khác ở đây có thể có hoặc không liên quan đến giao dịch xung quanh". Chắc chắn những gì trong đó ảnh hưởng rất lớn đến cách hành xử của mã?
RichardOD

2
"Số 2 không xảy ra vì chỉ có một kết nối tại một thời điểm" - # 2 không nói rằng kết nối thứ hai cần được mở cùng một lúc, chỉ là nó cần được ghi danh trong cùng một giao dịch.
Joe

3
Cảm ơn bạn rất nhiều vì đã báo cáo lại với Cập nhật 4 cho thấy mức độ leo thang có thể xảy ra chỉ với một SqlConnection duy nhất. Đây chính xác là những gì tôi đã chạy vào mặc dù cẩn thận đảm bảo rằng chỉ một SqlConnection được sử dụng. Thật tuyệt khi biết đó là máy tính điên rồ chứ không phải tôi. :-)
Oran Dennison

Về mặt nhóm kết nối, nếu chúng ta có nhiều kết nối (và được lồng nếu cần thiết) nếu chúng ta mở và đóng cùng một lúc, chúng ta sẽ sử dụng 1 tài nguyên nhóm kết nối thực hoặc 1 cho mỗi kết nối, tôi đang cố gắng hợp lý hóa điều này để xác định có hay không có phạm vi kết nối "có thể liệt kê" thích hợp (mà tôi muốn tránh)
brumScouse

1
Các kết nối lồng nhau trong cùng phạm vi giao dịch sẽ thúc đẩy giao dịch phân tán. Từ máy chủ SQL 2008 trở lên, nhiều kết nối (không lồng nhau) trong cùng một phạm vi giao dịch sẽ không được quảng bá đến một transaciton phân tán.
PreguntonCojoneroCabrón

Câu trả lời:


71

SQL Server 2008 có thể sử dụng nhiều SQLConnections trong một TransactionScopemà không cần leo thang, miễn là các kết nối không được mở cùng một lúc, điều này sẽ dẫn đến nhiều kết nối TCP "vật lý" và do đó cần phải leo thang.

Tôi thấy một số nhà phát triển của bạn có SQL Server 2005 và những người khác có SQL Server 2008. Bạn có chắc chắn đã xác định chính xác cái nào đang leo thang và cái nào không?

Giải thích rõ ràng nhất sẽ là các nhà phát triển với SQL Server 2008 là những người không leo thang.


Vâng, các chi tiết là chính xác, và có ai thực sự nhìn vào mã? Có hai kết nối trong phạm vi giao dịch, tuy nhiên, chỉ có một kết nối được kích hoạt và mở tại một thời điểm duy nhất. Ngoài ra, không, DTC không chạy trên các máy đang hoạt động.
Yoopergeek

1
"Tuy nhiên, chỉ có một kết nối duy nhất được kích hoạt và mở tại một thời điểm duy nhất" - tại sao điều đó có liên quan? Với SQL2005, nếu bạn mở nhiều hơn một kết nối trong phạm vi giao dịch, bạn sẽ leo thang cho dù chúng có mở đồng thời hay không. Đó là logic nếu bạn nghĩ về nó.
Joe

Bây giờ, bạn và những người làm báo giờ đã đoán tôi lần thứ hai và tôi nóng lòng muốn làm việc vào thứ Hai và kiểm tra các máy cá nhân của họ chặt chẽ hơn và đảm bảo các phiên bản SQL Server được báo cáo trước đó.
Yoopergeek

19
Bạn và hwiechers là đúng. Tôi có trứng trên khắp mặt. Cảm ơn bạn đã đánh tôi với đầu mối. :) Bởi vì bạn là người đầu tiên, bạn nhận được câu trả lời. Tuy nhiên, tôi muốn thêm một điểm làm rõ - SQL2008 cho phép mở nhiều kết nối, nhưng không phải cùng một lúc. Vẫn chỉ có thể có một kết nối duy nhất mở tại bất kỳ thời điểm nào hoặc Giao dịch viên sẽ chuyển lên DTC.
Yoopergeek

@Yoopergeek Tôi có thể xác minh rằng "không cùng lúc" của bạn là quan trọng và được chỉnh sửa câu trả lời của @Joe. Theo dõi các kết nối TCP trong khi kiểm tra cho thấy kết nối TCP cũ sẽ được sử dụng lại khi các kết nối không được sử dụng cùng một lúc, và do đó TransactionScopecó thể thực hiện với một bên duy nhất COMMITở phía máy chủ, điều này sẽ khiến việc leo thang trở nên thừa.
Eugene Beresovsky

58

Kết quả nghiên cứu của tôi về chủ đề này:

nhập mô tả hình ảnh ở đây

Xem Tránh nâng mức không mong muốn đối với các giao dịch phân tán

Tôi vẫn đang điều tra hành vi leo thang của Oracle: Các giao dịch trải dài trên nhiều kết nối đến cùng một DB có leo thang đến DTC không?


1
Cảm ơn đã chia sẻ nghiên cứu của bạn. Nó thực sự có ích. Thêm một truy vấn nhanh. Có gì khác biệt giữa TransactionScope () và sqlConnection.BeginTransaction ()?
Baig

Theo yêu cầu tính năng này , ODAC 12C giờ đây sẽ hoạt động như SQL 2008, không được quảng bá để phân phối khi sử dụng các kết nối liên tiếp đến cùng một nguồn dữ liệu.
Frédéric

31

Mã đó sẽ gây ra sự leo thang khi kết nối với năm 2005.

Kiểm tra tài liệu trên MSDN - http://msdn.microsoft.com/en-us/l Library / ms172070.aspx

Giao dịch có thể quảng bá trong SQL Server 2008

Trong phiên bản 2.0 của .NET Framework và SQL Server 2005, việc mở kết nối thứ hai bên trong TransactionScope sẽ tự động thúc đẩy giao dịch thành một giao dịch phân tán đầy đủ, ngay cả khi cả hai kết nối đang sử dụng các chuỗi kết nối giống hệt nhau. Trong trường hợp này, một giao dịch phân tán sẽ thêm chi phí không cần thiết làm giảm hiệu suất.

Bắt đầu với SQL Server 2008 và phiên bản 3.5 của .NET Framework, các giao dịch cục bộ không còn được quảng bá cho các giao dịch phân tán nếu một kết nối khác được mở trong giao dịch sau khi đóng giao dịch trước đó. Điều này không yêu cầu thay đổi mã của bạn nếu bạn đang sử dụng nhóm kết nối và tranh thủ trong các giao dịch.

Tôi không thể giải thích tại sao Dev 3: Windows 7 x64, SQL2005 thành công và Dev 4: Windows 7 x64 không thành công. Bạn có chắc chắn rằng đó không phải là cách khác?


10

Tôi không biết tại sao câu trả lời này đã bị xóa nhưng dường như có một số thông tin liên quan.

đã trả lời 04 Tháng Tám '10 17:42 Eduardo

  1. Đặt Enlist = false trên chuỗi kết nối để tránh tự động nhập ngũ khi giao dịch.

  2. Thủ công kết nối với tư cách là người tham gia trong phạm vi giao dịch. [ bài viết gốc đã lỗi thời] hoặc làm điều này: Cách ngăn quảng cáo MSDTC tự động [archive.is]



2

Tôi không chắc chắn nếu kết nối lồng nhau là vấn đề. Tôi đang gọi một phiên bản cục bộ của máy chủ SQL và nó không tạo ra 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();
        }
    }

Phiên bản SQL Server nào bạn đang sử dụng? Tôi tự hỏi nếu câu trả lời của @Peter Meinl cần được cập nhật để phản ánh bất kỳ thay đổi nào được thực hiện trong năm 2008R2 và / hoặc Denali.
Yoopergeek

Tôi đang sử dụng SQL Server 2008 R2.
Iftikhar Ali

Tôi tự hỏi nếu 2008 R2 là hành vi tốt hơn? Câu trả lời của @hwiechers cũng khiến tôi tự hỏi liệu phiên bản Khung bạn đang biên dịch có ngăn chặn sự leo thang hay không. Cuối cùng, tôi tự hỏi nếu nó là một cá thể R2 cục bộ làm cho bất kỳ sự khác biệt. Tôi ước mình có thời gian / tài nguyên để điều tra xem điều này đã thay đổi như thế nào với việc phát hành 2008 R2 và SQL Server 2012.
Yoopergeek

Không chắc chắn nếu kết nối lồng nhau là vấn đề? haha ... cũng nở hoa rồi!, tại sao mọi người lại làm tổ bằng cách sử dụng các câu lệnh khi không thực sự cần thiết, tôi sẽ không bao giờ biết.
Paul Zahra

1

TransactionScope luôn leo thang đến giao dịch DTC, nếu bạn sử dụng quyền truy cập nhiều hơn 1 kết nối bên trong. Cách duy nhất mà đoạn mã trên có thể hoạt động với DTC bị vô hiệu hóa là nếu rất có thể bạn sẽ nhận được cùng một kết nối từ nhóm kết nối cả hai lần.

"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." Bạn có chắc chắn rằng nó bị vô hiệu hóa;)


0

Hãy chắc chắn rằng ConnectionString của bạn không đặt pooling thành false. Điều này sẽ dẫn đến một kết nối mới cho mỗi SqlConnection mới trong TransactionScope và chuyển nó thành DTC.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.