2008-12-04 39 views
9

Đây là kiến ​​trúc hiện tại của mã nguồn phạm vi giao dịch của tôi. Chèn thứ ba ném một ngoại lệ .NET (Không phải là một ngoại lệ SQL) và nó không quay trở lại hai câu lệnh chèn trước đó. Tôi đang làm gì sai?TransactionScope không quay trở lại giao dịch

CHỈNH SỬA: Tôi đã xóa lần thử/bắt từ insert2 và insert3. Tôi cũng đã loại bỏ tiện ích xử lý ngoại lệ từ insert1 try/catch và đặt "throw ex". Nó vẫn không khôi phục lại giao dịch.

CHỈNH SỬA 2: Tôi đã thêm thử/bắt lại phương thức Insert3 và chỉ cần đặt "ném" vào câu lệnh bắt. Nó vẫn không khôi phục lại giao dịch.

UPDATE: Dựa trên những phản hồi tôi nhận được, lớp "SqlHelper" đang sử dụng các đối tượng SqlConnection để thiết lập một kết nối đến cơ sở dữ liệu, sau đó tạo ra một đối tượng SqlCommand, thiết lập thuộc tính CommandType để "StoredProcedure" và gọi ExecuteNonQuery phương pháp của SqlCommand.

Tôi cũng không thêm giao dịch Binding = Explicit Unbind vào chuỗi kết nối hiện tại. Tôi sẽ thêm điều đó trong bài kiểm tra tiếp theo của mình.

public void InsertStuff() 
{ 
    try 
    { 
     using(TransactionScope ts = new TransactionScope()) 
     { 
      //perform insert 1 
      using(SqlHelper sh = new SqlHelper()) 
      { 
       SqlParameter[] sp = { /* create parameters for first insert */ }; 

       sh.Insert("MyInsert1", sp); 
      } 

      //perform insert 2 
      this.Insert2(); 

      //perform insert 3 - breaks here!!!!! 
      this.Insert3(); 

      ts.Complete();    
     } 
    } 
    catch(Exception ex) 
    { 
     throw ex; 
    } 
} 

public void Insert2() 
{ 
    //perform insert 2 
    using(SqlHelper sh = new SqlHelper()) 
    { 
     SqlParameter[] sp = { /* create parameters for second insert */ }; 

     sh.Insert("MyInsert2", sp); 
    } 
} 

public void Insert3() 
{ 
    //perform insert 3 
    using(SqlHelper sh = new SqlHelper()) 
    { 
     SqlParameter[] sp = { /*create parameters for third insert */ }; 

     sh.Insert("MyInsert3", sp); 
    } 
} 
+0

Tôi không muốn nghi ngờ về kỹ năng phát triển của bạn, v.v ... nhưng bạn kiểm tra xem giao dịch đã quay trở lại như thế nào? Có thể giao dịch đang hoạt động chính xác nhưng bạn đang hiểu sai kết quả. Có lẽ cái gì khác đang xảy ra và chúng tôi/bạn đang sủa cây sai? –

+0

hy vọng điều này sẽ giúp: http://stackoverflow.com/questions/28191333/error-in-ambient-transaction-doesnt-rollback-the-transaction/28258935#28258935 –

Trả lời

6

Dường như bạn đang bắt ngoại lệ trong Insert3() để mã của bạn tiếp tục sau cuộc gọi. Nếu bạn muốn khôi phục lại, bạn sẽ cần để cho bong bóng ngoại lệ lên đến khối try/catch trong thói quen chính để câu lệnh ts.Complete() không bao giờ được gọi.

+0

vì vậy, tôi nên xóa câu lệnh try/catch khỏi chèn 2 và 3? –

+0

Có. Hoặc ném lại ngoại lệ hoặc ngoại lệ khác. – tvanfosson

+0

vâng, bạn không xử lý ngoại lệ bên gọi điện thoại chỉ là tiếp tục .... cũng..của họ bất kỳ giao dịch nào được khai báo trong sqlHelper? ... Tôi đưa ra một vấn đề khi tôi giao dịch được khai báo trong trợ giúp của tôi và Để loại bỏ nó. –

1

Một cuộn ngược tiềm ẩn sẽ chỉ xảy ra nếu việc sử dụng được thoát mà không cần gọi ts.complete. Bởi vì bạn đang xử lý ngoại lệ trong Insert3() ngoại lệ không bao giờ gây ra một câu lệnh using để thoát.

Hoặc rethrow các ngoại lệ hoặc thông báo cho người gọi rằng một rollback là cần thiết (làm thay đổi chữ ký của Insert3() để bool Insert3()?)

+0

Điều đó sẽ giải thích tại sao khi gỡ lỗi và nhấn dừng trước .Complete() được gọi là giao dịch không được cuộn lại (vì trong khi .Complete() không được gọi hoặc cũng không .Dispose()). Tôi đã đọc một số câu trả lời và bạn là người duy nhất đề cập đến điều này. +1 –

1

(dựa trên phiên bản chỉnh sửa mà không nuốt ngoại lệ)

Các hoạt động mất bao lâu? Nếu có bất kỳ hoạt động nào trong số đó chạy rất dài, có thể tính năng Transaction Binding lỗi đã cắn bạn - tức là kết nối đã bị tách rời. Thử thêm Transaction Binding=Explicit Unbind vào chuỗi kết nối.

+0

Tôi đã cập nhật câu hỏi dựa trên câu trả lời của bạn –

+0

Không có súc sắc. Tôi đã thêm Explicit Unbind vào chuỗi kết nối và nó vẫn không khôi phục –

23

Tôi cũng gặp phải sự cố tương tự. Vấn đề của tôi xảy ra vì SqlConnection tôi đã sử dụng trong SqlCommands của tôi đã được mở trước khi TransactionScope được tạo ra, vì vậy nó không bao giờ được nhập ngũ trong TransactionScope như một giao dịch.

Có thể lớp SqlHelper đang sử dụng lại một cá thể của SqlConnection được mở trước khi bạn nhập khối TransactionScope của mình?

+0

Cảm ơn - bạn đã giải quyết được vấn đề của mình. ;) – MojoDK

0

Tôi không thấy lớp trợ giúp của bạn, nhưng phạm vi giao dịch cuộn lại nếu bạn không gọi câu lệnh hoàn chỉnh ngay cả khi bạn gặp lỗi từ mã .NET. Tôi đã sao chép một ví dụ cho bạn. Bạn có thể đang làm điều gì sai trong khi gỡ lỗi. Ví dụ này có lỗi trong mã .net và khối catch tương tự như của bạn.

private static readonly string _connectionString = ConnectionString.GetDbConnection(); 

    private const string inserttStr = @"INSERT INTO dbo.testTable (col1) VALUES(@test);"; 

     /// <summary> 
     /// Execute command on DBMS. 
     /// </summary> 
     /// <param name="command">Command to execute.</param> 
     private void ExecuteNonQuery(IDbCommand command) 
     { 
      if (command == null) 
       throw new ArgumentNullException("Parameter 'command' can't be null!"); 

      using (IDbConnection connection = new SqlConnection(_connectionString)) 
      { 
       command.Connection = connection; 
       connection.Open(); 
       command.ExecuteNonQuery(); 
      } 
     } 

     public void FirstMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello1")); 


       ExecuteNonQuery(command); 

     } 

     public void SecondMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello2")); 


       ExecuteNonQuery(command); 

     } 

     public void ThirdMethodCauseNetException() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello3")); 


       ExecuteNonQuery(command); 
      int a = 0; 
      int b = 1/a; 

     } 

    public void MainWrap() 
    { 


     TransactionOptions tso = new TransactionOptions(); 
     tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; 
     //TransactionScopeOption.Required, tso 
     try 
     { 
      using (TransactionScope sc = new TransactionScope()) 
      { 
       FirstMethod(); 
       SecondMethod(); 
       ThirdMethodCauseNetException(); 
       sc.Complete(); 
      } 
     } 
     catch (Exception ex) 
     { 
      logger.ErrorException("eee ",ex); 

     } 
    } 

Nếu bạn muốn gỡ lỗi giao dịch của bạn, bạn có thể sử dụng kịch bản này để xem ổ khóa và tình trạng chờ đợi, vv

SELECT 
request_session_id AS spid, 
CASE transaction_isolation_level 
WHEN 0 THEN 'Unspecified' 
WHEN 1 THEN 'ReadUncomitted' 
WHEN 2 THEN 'Readcomitted' 
WHEN 3 THEN 'Repeatable' 
WHEN 4 THEN 'Serializable' 
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL , 
resource_type AS restype, 
resource_database_id AS dbid, 
DB_NAME(resource_database_id) as DBNAME, 
resource_description AS res, 
resource_associated_entity_id AS resid, 
CASE 
when resource_type = 'OBJECT' then OBJECT_NAME(resource_associated_entity_id) 
ELSE 'N/A' 
END as ObjectName, 
request_mode AS mode, 
request_status AS status 
FROM sys.dm_tran_locks l 
left join sys.dm_exec_sessions s on l.request_session_id = s.session_id 
where resource_database_id = 24 
order by spid, restype, dbname; 

Bạn sẽ thấy một SPID cho hai cuộc gọi phương thức trước khi gọi phương thức ngoại lệ.

two calls before exception

mức mặc định cách ly là serializable. You can read more about locks and transactions here

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