2013-03-08 31 views
10

Tôi gặp lỗi sau một lần trong đơn đăng ký của mình.SQLTransaction đã hoàn thành lỗi

Thao tác SQLTransaction này đã hoàn tất; nó không còn có thể sử dụng được

Dấu vết ngăn được đính kèm bên dưới - Nó nói về Zombie CheckRollback.

Lỗi trong mã là gì?

Lưu ý: Lỗi này chỉ xảy ra một lần.

CẬP NHẬT

Từ MSDN - SqlTransaction.Rollback Method

Một Rollback tạo ra một InvalidOperationException nếu kết nối bị chấm dứt hoặc nếu giao dịch đã được cuộn lại trên máy chủ.

Từ Zombie check on Transaction - Error

Một trong những lý do thường gặp nhất Tôi đã thấy lỗi này hiển thị trong ứng dụng khác nhau là, chia sẻ SqlConnection trên ứng dụng của chúng tôi.

public int SaveUserLogOnInfo(int empID) 
{ 
     int? sessionID = null; 
     using (SqlConnection connection = new SqlConnection(connectionString)) 
     { 
      connection.Open(); 
      SqlTransaction transaction = null; 
      try 
      { 
       transaction = connection.BeginTransaction(); 
       sessionID = GetSessionIDForAssociate(connection, empID, transaction); 

        //Other Code 

       //Commit 
       transaction.Commit(); 
      } 
      catch 
      { 
       //Rollback 
       if (transaction != null) 
       { 
        transaction.Rollback(); 
        transaction.Dispose(); 
        transaction = null; 
       } 

       //Throw exception 
       throw; 
      } 
      finally 
      { 
       if (transaction != null) 
       { 
        transaction.Dispose(); 
       } 
      } 
     } 

     return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture); 

    } 

Stack Trace

enter image description here


THAM KHẢO:

  1. What is zombie transaction?
  2. Zombie check on Transaction - Error
  3. SqlTransaction has completed
  4. http://forums.asp.net/t/1579684.aspx/1
  5. "This SqlTransaction has completed; it is no longer usable."... configuration error?
  6. dotnet.sys-con.com - SqlClient Connection Pooling Exposed
  7. Thread abort leaves zombie transactions and broken SqlConnection

+1

Ngoại lệ khiến mã của bạn tiếp cận 'bắt' là gì? – Maarten

+1

Trong trường hợp này, bạn nên sử dụng câu lệnh 'sử dụng' cho giao dịch của mình. Xem http://stackoverflow.com/questions/1127830/why-use-a-using-statement-with-a-sqltransaction – Maarten

+1

@Maarten công bằng, OP * không * đảm bảo rằng nó được xử lý; nhưng tôi đồng ý rằng * not * bằng cách sử dụng 'using' làm cho nó quá phức tạp –

Trả lời

5

Bạn nên để lại một số công việc cho trình biên dịch, để bọc nó trong một số try/catch/finally cho bạn.

Ngoài ra, bạn có thể mong đợi rằng Rollback đôi khi có thể ném ngoại lệ, nếu sự cố xảy ra ở giai đoạn Commit hoặc nếu kết nối với máy chủ bị hỏng. Vì lý do đó bạn nên quấn nó vào một số try/catch.

try 
{ 
    transaction.Rollback(); 
} 
catch (Exception ex2) 
{ 
    // This catch block will handle any errors that may have occurred 
    // on the server that would cause the rollback to fail, such as 
    // a closed connection. 
    Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType()); 
    Console.WriteLine(" Message: {0}", ex2.Message); 
} 

Điều này được sao chép chính xác từ MSDN documentation page for Rollback method.

Tôi thấy rằng bạn lo lắng rằng bạn có giao dịch zombie. Trong trường hợp bạn dán, nó không có vẻ như bạn có một vấn đề. Giao dịch của bạn đã hoàn tất và bạn sẽ không còn liên quan gì đến giao dịch đó nữa. Xóa các tham chiếu đến nó nếu bạn giữ chúng và quên nó đi.


Từ MSDN - SqlTransaction.Rollback Method

Một Rollback tạo ra một InvalidOperationException nếu kết nối bị chấm dứt hoặc nếu giao dịch đã được cuộn lại trên máy chủ.

rethrow một ngoại lệ mới nói cho người dùng rằng dữ liệu có thể không được lưu, và hỏi cô ấy để làm mới và rà soát

+0

Có một cảnh báo quan trọng trong phân tích mã, nếu tôi nuốt ngoại lệ. Điều đó có nghĩa là nếu tôi không 'ném' ngoại lệ 'catch'. – Lijo

+0

Sau đó, bạn có vấn đề với chính sách phân tích của mình. Tôi không thể tin rằng bạn không cho phép xử lý ngoại lệ thực tế? Bạn có ném tất cả ngoại lệ cho người dùng không? –

+0

Có, tôi cần phải ghi lại ngoại lệ và ném nó vào giao diện người dùng. Tôi ném ngoại lệ tùy chỉnh của mình, thường là trong ứng dụng khách. – Lijo

6

Lưu ý: Lỗi này chỉ xảy ra một lần.

thì rất khó để nói nhiều; nó có thể chỉ đơn giản là các // Other Code vv chỉ đơn giản là đã lâu, và toàn bộ điều đã bị giết. Có thể kết nối của bạn đã chết, hoặc quản trị viên đã cố ý giết nó vì bạn đã chặn.

Lỗi trong mã là gì?

quá phức tạp; nó có thể đơn giản hơn nhiều:

using (var connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    using(var transaction = connection.BeginTransaction()) 
    { 
     try 
     { 
      sessionID = GetSessionIDForAssociate(connection, empID, transaction); 
      //Other Code 
      transaction.Commit(); 
     } 
     catch 
     { 
      transaction.Rollback(); 
      throw; 
     } 
    } 
} 

ít mã hơn để nhận sai.

+3

trong trường hợp của bạn, bạn có thể lưu nhiều dòng hơn, nếu bạn loại bỏ try catch .. bằng cách sử dụng câu lệnh" using ", một giao dịch sẽ tự động được lùi lại nếu một ngoại lệ xảy ra .. xem http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.aspx – nWorx

+0

Cảm ơn. Nhưng tôi không hiểu tại sao mã được đề xuất sẽ giải quyết vấn đề. Có phải vì bạn không gọi là 'Vứt bỏ()'? – Lijo

+0

@nWorx thậm chí tốt hơn –

0

Thông báo này chỉ đơn giản là vì bạn đã viết code mà ném một ngoại lệ sau khi giao dịch có đã được cam kết thành công. Vui lòng thử kiểm tra mã bạn đã viết sau phương thức Commit hoặc bạn có thể xử lý bằng cách sử dụng Try..Catch và cuối cùng là Blocks :).

1

Tôi đã gặp phải lỗi này một lần và tôi bị kẹt và không thể biết điều gì đang xảy ra. Trên thực tế tôi đã xóa một bản ghi và trong thủ tục lưu trữ tôi đã không xóa con của nó và đặc biệt là tuyên bố xóa trong Stored Procedure là bên trong ranh giới Transaction. Tôi đã xóa mã giao dịch đó khỏi quy trình được lưu trữ và loại bỏ Lỗi này của “This SqlTransaction has completed; it is no longer usable.”

1

Tôi sử dụng mã bên dưới có thể tạo lại lỗi này, tôi sử dụng 1000 tác vụ để thực thi Sql, sau khoảng 300 tác vụ Đã hoàn tất thành công, ngoại lệ về timeout error bắt đầu xảy ra trên ExecuteNonQuery(),

thì lỗi tiếp theo This SqlTransaction has completed sẽ xảy ra trên transaction.RollBack(); và gọi stack của nó cũng chứa ZombieCheck().

(Nếu một chương trình có 1000 tác vụ áp lực không đủ, bạn có thể thực thi nhiều tệp exe được biên dịch cùng một lúc, hoặc thậm chí sử dụng nhiều máy tính thực hiện cho một DataBase.)

Vì vậy, tôi đoán một trong những lý do gây ra lỗi này có thể là điều gì đó sai trong Kết nối, sau đó gây ra lỗi giao dịch cũng xảy ra.

Task[] tasks = new Task[1000]; 
for (int i = 0; i < 1000; i++) 
{ 
    int j = i; 
    tasks[i] = new Task(() => 
     ExecuteSqlTransaction("YourConnectionString", j) 
     ); 
} 

foreach (Task task in tasks) 
{ 
    task.Start(); 
}  

/////////////  

public void ExecuteSqlTransaction(string connectionString, int exeSqlCou) 
{ 

    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 

     SqlCommand command = connection.CreateCommand(); 
     SqlTransaction transaction; 

     // Start a local transaction. 
     transaction = connection.BeginTransaction(); 

     // Must assign both transaction object and connection 
     // to Command object for a pending local transaction 
     command.Connection = connection; 
     command.Transaction = transaction; 

     try 
     { 
      command.CommandText = 
       "select * from Employee"; 
      command.ExecuteNonQuery(); 

      // Attempt to commit the transaction. 
      transaction.Commit(); 

      Console.WriteLine("Execute Sql to database." 
       + exeSqlCou); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Commit Exception Type: {0}", ex.GetType()); 
      Console.WriteLine(" Message: {0}", ex.Message); 


      // Attempt to roll back the transaction. 
      try 
      { 
       transaction.Rollback(); 
      } 
      catch (Exception ex2) 
      { 
       // This catch block will handle any errors that may have occurred 
       // on the server that would cause the rollback to fail, such as 
       // a closed connection. 
       Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType()); 
       Console.WriteLine(" Message: {0}", ex2.Message); 

      } 
     } 
    } 
} 

Bên cạnh đó tôi tìm thấy nếu tôi cam kết hai lần liên tiếp sẽ gọi ngoại lệ này là tốt.

 transaction.Commit(); 
     transaction.Commit(); 

Hoặc nếu kết nối đã đóng trước khi cam kết cũng sẽ gọi ra lỗi này.

 connection.Close(); 
     transaction.Commit(); 

Cập nhật:

tôi thấy nó lạ mà tôi tạo ra một bảng mới và chèn 500 ngàn dữ liệu vào nó,

sau đó sử dụng 100000 nhiệm vụ với select * from newtable sql, chạy 5 chương trình tại đồng thời, lần này, lỗi Thời gian chờ xảy ra, nhưng khi transaction.Rollback() nó không gọi số SQLTransaction has completed error.

nhưng nếu lỗi hết thời gian chờ xảy ra, hãy nhảy vào khối catch và trong khối catch làm lại transaction.Commit(), SQLTransaction has completed error sẽ xảy ra.

Các vấn đề liên quan