Giao dịch trong .net


144

Các thực tiễn tốt nhất để thực hiện giao dịch trong C # .Net 2.0 là gì. Các lớp nên được sử dụng là gì? Những cạm bẫy cần chú ý là gì ... Tất cả những gì cam kết và rollback thứ. Tôi mới bắt đầu một dự án mà tôi có thể cần thực hiện một số giao dịch trong khi chèn dữ liệu vào DB. Bất kỳ phản hồi hoặc liên kết cho ngay cả những thứ cơ bản về giao dịch đều được chào đón.


Dưới đây là một ví dụ điển hình về Giao dịch trong .NET trên codeproject để sử dụng làm khởi đầu.
Người bán Mitchel

Câu trả lời:


271

Có 2 loại giao dịch chính; giao dịch kết nối và giao dịch xung quanh. Một giao dịch kết nối (chẳng hạn như SqlTransaction) được gắn trực tiếp với kết nối db (chẳng hạn như SqlConnection), có nghĩa là bạn phải tiếp tục truyền kết nối xung quanh - trong một số trường hợp, nhưng không cho phép "tạo / sử dụng / giải phóng" sử dụng và không cho phép làm việc chéo db. Một ví dụ (được định dạng cho không gian):

using (IDbTransaction tran = conn.BeginTransaction()) {
    try {
        // your code
        tran.Commit();
    }  catch {
        tran.Rollback();
        throw;
    }
}

Không quá lộn xộn, nhưng giới hạn trong "kết nối" của chúng tôi. Nếu chúng ta muốn gọi ra các phương thức khác nhau, bây giờ chúng ta cần truyền "liên kết" xung quanh.

Thay thế là một giao dịch xung quanh; mới trong .NET 2.0, đối tượng TransactionScope (System.Transilities.dll) cho phép sử dụng trên một loạt các hoạt động (nhà cung cấp phù hợp sẽ tự động tranh thủ trong giao dịch xung quanh). Điều này giúp dễ dàng phù hợp với retro với mã hiện tại (không giao dịch) và nói chuyện với nhiều nhà cung cấp (mặc dù DTC sẽ tham gia nếu bạn nói chuyện với nhiều hơn một).

Ví dụ:

using(TransactionScope tran = new TransactionScope()) {
    CallAMethodThatDoesSomeWork();
    CallAMethodThatDoesSomeMoreWork();
    tran.Complete();
}

Lưu ý ở đây rằng hai phương thức có thể xử lý các kết nối của riêng chúng (mở / sử dụng / đóng / hủy), nhưng chúng sẽ âm thầm trở thành một phần của giao dịch xung quanh mà không cần chúng tôi phải chuyển bất kỳ thứ gì vào.

Nếu lỗi mã của bạn, Dispose () sẽ được gọi mà không có Complete (), vì vậy nó sẽ được khôi phục. Vv lồng nhau dự kiến ​​sẽ được hỗ trợ, mặc dù bạn không thể hoàn trả giao dịch bên trong nhưng vẫn hoàn thành giao dịch bên ngoài: nếu bất kỳ ai không hài lòng, giao dịch sẽ bị hủy bỏ.

Ưu điểm khác của TransactionScope là nó không chỉ gắn với cơ sở dữ liệu; bất kỳ nhà cung cấp nhận thức giao dịch có thể sử dụng nó. WCF chẳng hạn. Hoặc thậm chí có một số mô hình đối tượng tương thích với TransactionScope xung quanh (ví dụ: các lớp .NET có khả năng khôi phục - có lẽ dễ dàng hơn một vật lưu niệm, mặc dù tôi chưa bao giờ sử dụng phương pháp này).

Tất cả trong tất cả, một đối tượng rất, rất hữu ích.

Một số hãy cẩn thận:

  • Trên SQL Server 2000, một Giao diện viên sẽ chuyển đến DTC ngay lập tức; điều này đã được sửa trong SQL Server 2005 trở lên, nó có thể sử dụng LTM (ít chi phí hơn nhiều) cho đến khi bạn nói chuyện với 2 nguồn, v.v., khi nó được nâng lên thành DTC.
  • Có một trục trặc có nghĩa là bạn có thể cần phải điều chỉnh chuỗi kết nối của mình

CSLA .NET 2.0 hỗ trợ đối tượng TransactionScope!
Binoj Antony 17/03/2016

Vấn đề ở đây là khi bạn có một giao dịch trong phương thức đầu tiên và phương thức này (đóng gói) không biết liệu sẽ được gọi từ một giao dịch mẹ hay không.
Eduardo Molteni

1
@Eduardo - đó không phải là vấn đề khi sử dụng TransactionScope, làm cho nó rất hấp dẫn. Các giao dịch như vậy làm tổ, và chỉ các cam kết ngoài cùng.
Marc Gravell

Tôi hy vọng bạn vẫn đang lắng nghe. Bạn nói rằng có "một số mô hình đối tượng tương thích với TransactionScope". Bạn có thể chỉ cho tôi một số trong số họ? Cám ơn.
Majkinetor

1
Một lần nữa Marc, một lời giải thích tuyệt vời. Khi bạn nói 'lồng dự kiến ​​được hỗ trợ' có phải là cho các khối giao dịch được xác định trong các phương thức (ví dụ CallAMethodThatDoesSomeWork ()) không? Hoặc với giao dịch được xác định bên ngoài, nó không bắt buộc?
Phil Cooper

11
protected void Button1_Click(object sender, EventArgs e)
   {


       using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True"))
       {
           connection1.Open();

           // Start a local transaction.
           SqlTransaction sqlTran = connection1.BeginTransaction();

           // Enlist a command in the current transaction.
           SqlCommand command = connection1.CreateCommand();
           command.Transaction = sqlTran;

           try
           {
               // Execute two separate commands.
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('a','b','c')";
               command.ExecuteNonQuery();
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('x','y','z')";
               command.ExecuteNonQuery();

               // Commit the transaction.
               sqlTran.Commit();
               Label3.Text = "Both records were written to database.";
           }
           catch (Exception ex)
           {
               // Handle the exception if the transaction fails to commit.
               Label4.Text = ex.Message;


               try
               {
                   // Attempt to roll back the transaction.
                   sqlTran.Rollback();
               }
               catch (Exception exRollback)
               {
                   // Throws an InvalidOperationException if the connection 
                   // is closed or the transaction has already been rolled 
                   // back on the server.
                   Label5.Text = exRollback.Message;

               }
           }
       }


   }

4

Bạn cũng có thể gói giao dịch vào quy trình được lưu trữ của riêng mình và xử lý theo cách đó thay vì thực hiện giao dịch trong chính C #.


1

nếu bạn chỉ cần nó cho các công cụ liên quan đến db, một số Trình ánh xạ HOẶC (ví dụ NHibernate) hỗ trợ giao dịch ngoài hộp theo mặc định.


0

Nó cũng phụ thuộc vào những gì bạn cần. Đối với các giao dịch SQL cơ bản, bạn có thể thử thực hiện các giao dịch TSQL bằng cách sử dụng BEGIN TRANS và CAMIT TRANS trong mã của mình. Đó là cách dễ nhất nhưng nó có độ phức tạp và bạn phải cẩn thận để cam kết đúng (và rollback).

Tôi sẽ sử dụng một cái gì đó như

SQLTransaction trans = null;
using(trans = new SqlTransaction)
{
    ...
    Do SQL stuff here passing my trans into my various SQL executers
    ...
    trans.Commit  // May not be quite right
}

Bất kỳ thất bại nào sẽ đưa bạn ra khỏi usinggiao dịch và giao dịch sẽ luôn cam kết hoặc khôi phục (tùy thuộc vào những gì bạn bảo nó làm). Vấn đề lớn nhất mà chúng tôi gặp phải là đảm bảo nó luôn được cam kết. Việc sử dụng đảm bảo phạm vi của giao dịch bị hạn chế.

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.