2010-05-26 32 views
31

Tôi gặp sự cố và tất cả các bài viết hoặc ví dụ tôi thấy dường như không quan tâm đến nó.Không thể truy cập đối tượng SqlTransaction để khôi phục trong khối catch

Tôi muốn thực hiện một số hành động cơ sở dữ liệu trong giao dịch. Những gì tôi muốn làm là rất giống với hầu hết các ví dụ:

using (SqlConnection Conn = new SqlConnection(_ConnectionString)) 
{ 
    try 
    { 
     Conn.Open(); 
     SqlTransaction Trans = Conn.BeginTransaction(); 

     using (SqlCommand Com = new SqlCommand(ComText, Conn)) 
     { 
      /* DB work */ 
     } 
    } 
    catch (Exception Ex) 
    { 
     Trans.Rollback(); 
     return -1; 
    } 
} 

Nhưng vấn đề là các SqlTransaction Trans được khai báo bên trong khối try. Vì vậy, nó không thể truy cập trong khối catch(). Hầu hết các ví dụ chỉ cần thực hiện Conn.Open()Conn.BeginTransaction() trước khối try, nhưng tôi nghĩ đó là một chút rủi ro, vì cả hai có thể ném nhiều ngoại lệ.

Tôi có sai hay hầu hết mọi người chỉ bỏ qua rủi ro này? Giải pháp nào tốt nhất để có thể khôi phục, nếu một ngoại lệ xảy ra?

+2

P.S. bạn có chắc chắn muốn trả về -1 (mã lỗi) thay vì ném một ngoại lệ không? –

Trả lời

55
using (var Conn = new SqlConnection(_ConnectionString)) 
{ 
    SqlTransaction trans = null; 
    try 
    { 
     Conn.Open(); 
     trans = Conn.BeginTransaction(); 

     using (SqlCommand Com = new SqlCommand(ComText, Conn, trans)) 
     { 
      /* DB work */ 
     } 
     trans.Commit(); 
    } 
    catch (Exception Ex) 
    { 
     if (trans != null) trans.Rollback(); 
     return -1; 
    } 
} 

hoặc bạn có thể đi thậm chí sạch hơn và dễ dàng hơn và sử dụng này:

using (var Conn = new SqlConnection(_ConnectionString)) 
{ 
    try 
    { 
     Conn.Open(); 
     using (var ts = new System.Transactions.TransactionScope()) 
     { 
      using (SqlCommand Com = new SqlCommand(ComText, Conn)) 
      { 
       /* DB work */ 
      } 
      ts.Complete(); 
     } 
    } 
    catch (Exception Ex) 
    {  
     return -1; 
    } 
} 
+0

Phiên bản thứ hai có thực sự thực hiện khôi phục khi có ngoại lệ không? Chỉnh sửa: OK, sau khi đọc tài liệu tôi đã nhìn thấy nó. – Marks

+1

Trong ví dụ đầu tiên của bạn, bạn không cần phải xác định rằng sqlcommand được liên kết với giao dịch? chẳng hạn như 'sử dụng (SqlCommand Com = new SqlCommand (ComText, Conn, ** trans **))'? Hay điều đó không cần thiết? nó có liên quan ngầm không? –

+0

Vâng, cảm ơn. Với TransactionScope, bạn không, nhưng tôi đã bỏ qua nó từ ví dụ đầu tiên của tôi. Đã chỉnh sửa cho phù hợp. –

6

sử dụng này

using (SqlConnection Conn = new SqlConnection(_ConnectionString)) 
{ 
    SqlTransaction Trans = null; 
    try 
    { 
     Conn.Open(); 
     Trans = Conn.BeginTransaction(); 

     using (SqlCommand Com = new SqlCommand(ComText, Conn)) 
     { 
      /* DB work */ 
     } 
    } 
    catch (Exception Ex) 
    { 
     if (Trans != null) 
      Trans.Rollback(); 
     return -1; 
    } 
} 

BTW - Bạn đã không cam kết nó trong trường hợp xử lý thành công

1

Các mẫu của Microsoft, đặt đầu tiên ra bên ngoài của try/catch see this msdn link. Tôi giả định rằng phương thức BeginTransaction hoặc là ném một ngoại lệ HOẶC bắt đầu một giao dịch nhưng không bao giờ cả hai (mặc dù tài liệu không nói điều này là không thể).

Tuy nhiên, bạn có thể tốt hơn của việc sử dụng TransactionScope trong đó quản lý rất nhiều (không như vậy) nâng nặng cho bạn: this link

3
using (SqlConnection Conn = new SqlConnection(_ConnectionString)) 
{ 
    try 
    { 
     Conn.Open(); 
     SqlTransaction Trans = Conn.BeginTransaction(); 

     try 
     { 
      using (SqlCommand Com = new SqlCommand(ComText, Conn)) 
      { 
       /* DB work */ 
      } 
     } 
     catch (Exception TransEx) 
     { 
      Trans.Rollback(); 
      return -1; 
     } 
    } 
    catch (Exception Ex) 
    { 
     return -1; 
    } 
} 
+0

Trong khi có nhiều mã, điều này cung cấp mức chi tiết tốt nhất để có thể xác định lý do tại sao mỗi bước sẽ không thành công. Tuy nhiên, lưu ý rằng SqlCommand phải được liên kết với giao dịch. – JWilliams

8

tôi không thích cách gõ các loại và thiết lập các biến để null, vì vậy :

try 
{ 
    using (var conn = new SqlConnection(/* connection string or whatever */)) 
    { 
     conn.Open(); 

     using (var trans = conn.BeginTransaction()) 
     { 
      try 
      { 
       using (var cmd = conn.CreateCommand()) 
       { 
        cmd.Transaction = trans; 
        /* setup command type, text */ 
        /* execute command */ 
       } 

       trans.Commit(); 
      } 
      catch (Exception ex) 
      { 
       trans.Rollback(); 
       /* log exception and the fact that rollback succeeded */ 
      } 
     } 
    } 
} 
catch (Exception ex) 
{ 
    /* log or whatever */ 
} 

Và nếu bạn muốn chuyển sang MySql hoặc nhà cung cấp khác, bạn chỉ cần sửa đổi 1 dòng.

0
SqlConnection conn = null; 
SqlTransaction trans = null; 

try 
{ 
    conn = new SqlConnection(_ConnectionString); 
    conn.Open(); 
    trans = conn.BeginTransaction(); 
    /* 
    * DB WORK 
    */ 
    trans.Commit(); 
} 
catch (Exception ex) 
{ 
    if (trans != null) 
    { 
     trans.Rollback(); 
    } 
    return -1; 
} 
finally 
{ 
    if (conn != null) 
    { 
     conn.Close(); 
    } 
} 
Các vấn đề liên quan