2012-03-01 50 views
5

Tôi có cần phải gọi vứt bỏ trong khối cuối cùng cho SqlTransaction? Giả vờ nhà phát triển không sử dụng USING ở bất cứ đâu và chỉ cần thử/bắt.SqlTransaction có cần phải có Dispose được gọi là?

SqlTransaction sqlTrans = con.BeginTransaction(); 

try 
{ 
    //Do Work 
sqlTrans.Commit() 
} 
catch (Exception ex) 
     { 

      sqlTrans.Rollback(); 
     } 

finally 
     { 
      sqlTrans.Dispose(); 
      con.Dispose(); 
     } 
+0

không làm tổn thương. – Brian

+1

Nếu bạn không sử dụng 'using' xung quanh' sqlTrans' thì chắc chắn nó không bị tổn thương để gọi rõ ràng 'Dispose()' trên nó. –

+0

@Cory Có cần kiểm tra xem sqlTrans đã được xử lý trước khi gọi sqlTrans.Dispose() chưa? – Lijo

Trả lời

9

Tôi có cần sử dụng try-finally hoặc using để tránh xử lý SqlTransaction?

Nó không đau khi có nó. Điều này đúng với mọi lớp thực hiện IDisposable, nếu không nó sẽ không thực hiện giao diện này.

Nhưng thông thường, bộ thu gom rác sẽ xử lý nếu đối tượng không được tham chiếu nữa. Bởi vì tôi cũng không muốn gọi dispose trên mỗi biến thứ hai hoặc sử dụng using-statement ở khắp mọi nơi, nên luôn xem xét việc triển khai thực tế phương thức 'Dispose' của lớp học.

SqlTransaction.Dispose:

protected override void Dispose(bool disposing) 
{ 
    if (disposing) 
    { 
     SNIHandle target = null; 
     RuntimeHelpers.PrepareConstrainedRegions(); 
     try 
     { 
      target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection); 
      if (!this.IsZombied && !this.IsYukonPartialZombie) 
      { 
       this._internalTransaction.Dispose(); 
      } 
     } 
     catch (OutOfMemoryException e) 
     { 
      this._connection.Abort(e); 
      throw; 
     } 
     catch (StackOverflowException e2) 
     { 
      this._connection.Abort(e2); 
      throw; 
     } 
     catch (ThreadAbortException e3) 
     { 
      this._connection.Abort(e3); 
      SqlInternalConnection.BestEffortCleanup(target); 
      throw; 
     } 
    } 
    base.Dispose(disposing); 
} 

Nếu không có sự hiểu biết tất cả (hoặc bất cứ điều gì) những gì đang xảy ra ở đây tôi có thể nói rằng đây không chỉ là một đơn giản base.Dispose(disposing). Vì vậy, nó có thể là một ý tưởng tốt để đảm bảo rằng một SqlTransaction được xử lý.

Nhưng vì SqlConnection.BeginTransaction tạo giao dịch nó cũng có thể là một ý tưởng tốt để reflect này cũng:

public SqlTransaction BeginTransaction(IsolationLevel iso, string transactionName) 
{ 
    SqlStatistics statistics = null; 
    string a = ADP.IsEmpty(transactionName) ? "None" : transactionName; 
    IntPtr intPtr; 
    Bid.ScopeEnter(out intPtr, "<sc.SqlConnection.BeginTransaction|API> %d#, iso=%d{ds.IsolationLevel}, transactionName='%ls'\n", this.ObjectID, (int)iso, a); 
    SqlTransaction result; 
    try 
    { 
     statistics = SqlStatistics.StartTimer(this.Statistics); 
     SqlTransaction sqlTransaction = this.GetOpenConnection().BeginSqlTransaction(iso, transactionName); 
     GC.KeepAlive(this); 
     result = sqlTransaction; 
    } 
    finally 
    { 
     Bid.ScopeLeave(ref intPtr); 
     SqlStatistics.StopTimer(statistics); 
    } 
    return result; 
} 

Như bạn có thể nhìn thấy. Các GC cũng sẽ giữ cho kết nối còn sống khi một giao dịch được tạo ra. Nó cũng không giữ một tham chiếu đến giao dịch vì nó chỉ trả về nó. Do đó nó có thể không được xử lý ngay cả khi kết nối đã được xử lý. Một đối số khác để vứt bỏ giao dịch.

Bạn cũng có thể xem số TransactionScope class an toàn hơn BeginTransaction. Hãy xem this question để biết thêm thông tin.

+0

bạn cũng có thể muốn xem xét BeginSqlTransaction() và mã Connection.Dispose(). SqlTransaction có vẻ là một wrpapper xung quanh InternalTransaction của nó được xóa trong Connection.Dispose(). –

+1

Tôi trân trọng không đồng ý với nhận xét này 'Điều này đúng cho mọi lớp thực hiện IDisposable'. Điều gì về kiểm soát TableCell và các điều khiển HTML khác. Đó là khuyến cáo KHÔNG áp dụng 'sử dụng' trên chúng. – Lijo

+1

@Lijo: Điểm lấy, đó là quá chung chung. Bạn chỉ cần ghi đè việc triển khai hoặc sử dụng câu lệnh 'using' nếu bạn cần vứt bỏ một số tài nguyên không được quản lý như kết nối cơ sở dữ liệu. Một điều khiển thực hiện 'IDposable' bởi vì điều khiển (f.e. một' UserControl') có thể chứa các tài nguyên không được quản lý và nó sẽ được xử lý ở cuối vòng đời (trang đệ quy vào tất cả các điều khiển con). –

7

Trong trường hợp chung, mỗi đối tượng bạn xây dựng hoặc có được và sở hữu, bạn phải vứt bỏ.

Trong trường hợp cụ thể, có một số ngoại lệ, nhưng SqlTransaction không phải là một trong số chúng.

Theo the documentation of SqlTransaction.Dispose:

Giải phóng nguồn lực không được quản lý sử dụng bởi các DbTransaction và tùy chọn giải phóng các nguồn lực quản lý.

(tôi nhấn mạnh)

Kể từ khi tài liệu không ghi rõ rằng những nguồn lực không được quản lý được giải phóng khi bạn phát hành một cam kết hoặc một rollback, bạn sẽ cần phải định đoạt của đối tượng này.

0

Tôi nghĩ bạn chỉ có thể đóng kết nối. Tôi đã kiểm tra mã của BCL - có vẻ như các kết nối sẽ quan tâm đến giao dịch của nó - không cần phải đóng nó một cách rõ ràng.

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