2009-10-14 37 views
8

Tôi có một số nhầm lẫn cơ bản về cách giao dịch và msdtc hoạt động cùng nhau.nhầm lẫn về giao dịch và msdtc

Tôi có ứng dụng máy chủ cơ bản/ứng dụng winforms cơ bản. Ứng dụng sử dụng transactioncope để gói gọn một số lệnh sql được thực thi trên máy chủ sql.

Ứng dụng dường như hoạt động tốt khi tôi chỉ bật truy cập mạng msdtc trên máy chủ. Sau đó một ngày nó ngừng hoạt động nói rằng truy cập mạng không được kích hoạt.

Bây giờ có vẻ như tôi phải bật truy cập mạng msdtc trên cả máy khách và máy chủ để giao dịch hoạt động.

Dịch vụ khách hàng hoặc máy chủ msdtc có thực hiện giao dịch không? Hoặc có thể cả hai?

Có ai có hướng dẫn về việc liệu truy cập mạng msdtc là cần thiết trên cả máy khách và máy chủ hay chỉ máy chủ?

Trả lời

10

Nếu bạn đang sử dụng MSDTC, bạn sẽ cần ứng dụng khách (ứng dụng của bạn) và máy chủ (cơ sở dữ liệu) chạy cả MSDTC và cũng được cấu hình đúng cách.

Đây có thể là nguồn gây đau đặc biệt là khi giao dịch với tường lửa. Nếu bạn gặp sự cố, hãy xem Troubleshooting Problems with MSDTC. Nó nói về BizTalk nhưng nó áp dụng cho MSDTC nói chung. DTCPING cũng là bạn của bạn.

Bây giờ nếu bạn đang sử dụng SQL Server 2005 trở lên, chỉ truy cập một cơ sở dữ liệu, đang sử dụng một kết nối cơ sở dữ liệu và không chuyển giao dịch giữa các miền ứng dụng thì bạn không cần sử dụng MSDTC. Trong những trường hợp đó, người quản lý giao dịch System.Transactions sẽ quản lý các giao dịch của bạn cho bạn. Nếu xảy ra bất kỳ tình huống nào trước đó thì giao dịch sẽ được chuyển sang giao dịch phân phối (và người quản lý giao dịch sẽ là MSDTC). Xem Transaction Management Escalation để biết thêm thông tin.

Nói chung tốt nhất là tránh sử dụng MSDTC nếu bạn không cần đến nó. tức là nếu bạn chỉ xử lý một cơ sở dữ liệu SQL Server 2005+ duy nhất thì hãy thử thiết kế mã của bạn để không sử dụng MSDTC. Bên cạnh những rắc rối cấu hình, DTC áp đặt một hình phạt hiệu suất bởi vì tất cả các cuộc gọi đến MSDTC được ra khỏi quá trình kết hợp với chi phí của giao thức cam kết hai giai đoạn (mà MSDTC sử dụng).

Về những gì đang xảy ra trong tình huống cụ thể của bạn, thật khó để nói. Nếu mã của bạn không thay đổi, thì có lẽ các quy tắc tường lửa đã thay đổi? Tôi cũng đã thấy Windows Updates thay đổi cấu hình DTC (để bảo mật) gây ra sự cố.

Cập nhật Dựa trên Comment:

Đối với xúc tiến giao dịch giám sát hoặc leo thang, nếu bạn không sử dụng bất kỳ giao dịch phân tán tôi nghĩ bạn có thể sử dụng một số bộ đếm hiệu suất Transaction Coordinator Distributed để theo dõi các giao dịch đã cam kết. Nếu thử nghiệm bạn có thể tắt MSDTC và xem mã của bạn có bị lỗi không. Một cách khác là giám sát các giao dịch trong SQL Server. Từ góc độ mã hóa, bạn có thể thử xử lý sự kiện DistributedTransactionStarted và thực hiện một số thao tác ghi nhật ký (nhưng xóa mã đó trước khi đi vào sản xuất).

Để biết ví dụ về mã sử dụng một kết nối, hãy truy cập trang TransactionScope tại MSDN. Về cơ bản, tạo một TransactionScope, tạo một SqlConnection, làm một số việc với SqlConnection, đóng kết nối, gọi scope.Complete().

Lưu ý rằng nếu bạn đang sử dụng phương pháp Bộ tiếp hợp dữ liệu, chúng sẽ tự động quản lý kết nối của bạn để kết nối được đóng hoặc trả lại kết nối. Dù bằng cách nào, nếu một hoạt động khác được gọi thì giao dịch sẽ được chuyển sang giao dịch DTC. Xem System.Transactions and connection pooling để biết thêm chi tiết.

+0

Cảm ơn thông tin tuyệt vời. Tôi rất thích không sử dụng MSDTC. Tôi đang sử dụng sql2005, 1 db, không chuyển tên miền ứng dụng, nhưng không chắc chắn nếu tôi đang sử dụng 1 kết nối. Có thể đưa ra một ví dụ ngắn về một giao dịch với nhiều câu lệnh sql không được nâng lên dtc không? Có công cụ hay cách nào khác để biết các giao dịch của tôi có được nâng lên msdtc không? – muhan

7

Mở rộng trên @ giải thích Tuzo của, đây là một ví dụ về một lệnh đó sẽ luôn luôn leo thang:

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    scope.Complete(); 
} 

Trong thực tế, kết nối và lệnh sẽ được trong một lớp học, vv, nhưng bạn sẽ có được ý kiến. Ngay cả khi chuỗi kết nối đến cùng một cơ sở dữ liệu, nó sẽ leo thang bằng DTC, vì nó là hai kết nối. Giao dịch không leo thang sẽ là:

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    //...some other command, etc. 
    } 
    scope.Complete(); 
} 

Đây là mã tốt hơn, vì bạn mở kết nối, thực hiện những gì bạn cần và đóng càng sớm càng tốt. Điều này có nghĩa là bạn phải suy nghĩ qua việc quản lý kết nối của mình. Tùy thuộc vào ứng dụng của bạn, bạn có thể thực hiện điều này một cách khác nhau. Ví dụ:

using(var scope = new TransactionScope()) 
using(var conn = new SqlConnection(connString)) 
{ 
    conn.Open(); 
    var myService = new MyService(conn); 
    var myService2 = new MyService2(conn); 
    myService.DoSomething(); 
    myService2.DoSomething(); 
    scope.Complete(); 
} 

Có nhiều cách để thực hiện việc này. Khối ứng dụng truy cập dữ liệu thư viện doanh nghiệp và nhiều ORM khác nhau cũng có thể giúp bạn xử lý các kết nối và giao dịch hiệu quả hơn.

+1

Khối truy cập dữ liệu thư viện doanh nghiệp có thể giúp vì nó duy trì danh sách nội bộ của các giao dịch đang hoạt động và kết nối của chúng (trong lớp TransactionScopeConnections). Cùng một kết nối được sử dụng trong suốt thời gian của giao dịch, do đó giao dịch không chuyển sang giao dịch được phân phối. Nó cũng có lợi ích của việc làm cho giao diện của bạn sạch hơn kể từ khi bạn không cần phải vượt qua các kết nối xung quanh với mọi phương pháp mà cần phải sử dụng một kết nối cơ sở dữ liệu. –

+1

CHO người dùng SQLserver 2008: Ví dụ đầu tiên của mã của bạn sẽ không leo thang trên SQLserver 2008. Nó sẽ chỉ leo thang nếu bạn không đóng kết nối đầu tiên trước khi mở kết nối thứ hai (ví dụ: nếu bạn làm tổ 3 bằng cách sử dụng statament bên trong tuyên bố). – mipe34

0

Cập nhật: Tôi tìm thấy một bài viết giải thích lý do tại sao các giao dịch đang được quảng bá dưới dạng LTM thành MSDTC khi chỉ sử dụng cả GetData và Cập nhật trên cùng một bộ điều hợp dữ liệu trong TransactionScope cùng với giải pháp thay thế.

Các TableAdapters giao dịch + dứt khoát bài đăng blog http://blah.winsmarts.com/2006/06/18/the-definitive-tableadapters--transactions-blog-post.aspx

tôi hiểu được một phần về việc có nhiều kết nối mở cùng một lúc leo thang một giao dịch để được phân phối. Tuy nhiên, tôi đang gặp sự cố khi chỉ có một kết nối và một truy vấn đối với cơ sở dữ liệu đang leo thang nó. Không có bất kỳ giao dịch nào trong quy trình được lưu trữ. Nếu bất cứ ai có một đầu mối, tôi muốn nghe về nó. Từ ví dụ mã của tôi, "adapter.Update (table)" sẽ kích hoạt một giao dịch phân tán.

Tôi đã mang sự can đảm của mã ra khỏi dự án hiện tại của mình và đơn giản hóa hầu hết những gì đang diễn ra và tôi vẫn gặp sự cố tương tự. Điều này về cơ bản là tạo ra một tập dữ liệu với một bộ điều hợp bảng và thiết lập nó với một thủ tục được lưu trữ để chọn, chèn và xóa. Tôi chọn tất cả các bản ghi liên quan với một người dùng cụ thể. Sau đó, tùy thuộc vào nếu một "myPPID" tồn tại cho một trong các bản ghi, tôi thêm nó hoặc xóa nó. Sau đó tôi gọi phương thức cập nhật và xem giao dịch leo thang để được phân phối bằng cách xem Thống kê giao dịch trong các dịch vụ thành phần.

Tôi đang sử dụng Windows XP Pro SP3 và .Net Framework 3.5 cho chương trình khách hàng. Nó kết nối với một cơ sở dữ liệu SQL 2005 qua mạng LAN tới Windows Server 2003 R2 Enterprise Edition SP2.

private void button1_Click(object sender, EventArgs e) 
{ 
int userId = 3; 
int myPPId = 881; 
using (TransactionScope ts = new TransactionScope()) 
{ 
    using (DataSet1TableAdapters.AssignedPPTableAdapter adapter 
    = new MSDTCPromotionTest.DataSet1TableAdapters.AssignedPPTableAdapter()) 
    { 
     using (DataSet1.AssignedPPDataTable table = adapter.GetData(userId)) 
     { 
      DataSet1.AssignedPPRow row = table.FindByUserIdmyPPId(
       userId, myPPId); 
      if (row == null) 
      { 
       table.AddAssignedPPRow(userId, myPPId, string.Empty, 
        string.Empty, true); 
      } 
      else 
      { 
       row.Delete(); 
      } 
      adapter.Update(table); 
     } 
     ts.Complete(); 
    } 
} 
} 

Các chuỗi kết nối là không có gì đặc biệt:

<add name="ConnectionString" connectionString=" 
Data Source=devdb; 
Initial Catalog=&quot;TEST MSDTC&quot;; 
Integrated Security=True" 
providerName="System.Data.SqlClient" /> 

Ngoài ra, các thủ tục lưu trữ những cuộc gọi crud đơn giản.

Tạo:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Insert] 
(
    @UserId INT, 
    @myPPId int 
) 
AS 
SET NOCOUNT ON; 
INSERT INTO [UsermyPP] ([UserID],[myPPID],[DateCreated]) 
    VALUES (@UserId,@myPPId,GETutcDATE()) 

đọc:

ALTER procedure [dbo].[p_UserForm_AssignedPP_SelectByUserId] 
(
    @UserId int 
) 
AS 
SELECT 
    [UserId], 
    [myPPId], 
    '' Title, 
    '' Abbreviation, 
    0 IsArchived 
from 
    UsermyPP unpp 
where 
    unpp.[userid] = @UserId 

Xóa:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Delete] 
(
    @Original_UserId INT, 
    @Original_MyPPId INT 
) 
AS 
SET NOCOUNT ON; 
DELETE FROM usermypp WHERE [UserID] = @Original_UserId 
    AND [MyPPID] = @Original_MyPPId