在
NET
x 的 C#
NET
的各種語言中
有所謂的 using statement (如本 blog 上一篇帖子「使用ADO
NET 的NextResult 方法取得多個Result Set」的代碼范例)
可保證自動 dispose (釋放) unmanaged object (對象) 所占用的資源
包括因未處理的 exception 而造成區塊結束 (但 StackOverflowException 除外)
系統都會 dispose 資源
因此若您在 using 區塊中建立了數據庫的 connection
即無須再手動 close connection
亦無須再下 Connection
Dispose()
Command
Dispose() 等指令
根據 MSDN Library 和目前市面上幾本 ADO
NET
原文書都有提到
在 using 區塊中會自動去做 dispose 的動作
NET 的 garbage collector 會自動釋放不再使用的 managed resources 所占用的內存
不用程序員手動撰碼
但 unmanaged resources 則需要程序員自行下 Dispose() 去做處理
以讓對象徹底終止 unmanaged resources 的使用
例如傳統的做法
常會在 try
catch
finally pattern 中去呼叫 Dispose 方法
但若是數據庫的聯機
則必須有不同考慮
因為若任意下 Dispose 提早回收
也可能導致聯機無法有效地被重復引用
現在大部分的數據庫和 Data Provider 都有支持 Connection Pooling 機制
亦即在建立完數據庫的聯機後
當程序員呼叫 Close 方法關閉一個數據庫的 Connection 對象時
NET 的 Data Provider 並不會將這個對象所占用的內存空間釋放掉
而是將此對象暫存至 Pool 之中
以便待會可以再重復使用
若在設定時間 (默認為
秒) 內
沒有應用程序使用到此對象
或是呼叫了 Dispose 方法
則
NET Data Provider 才會真正關閉這個聯機
並由 Garbage Collector 自動將資源收回
因此
常有 web 程序員在網絡上各討論區提到
是否有必要在呼叫 Close 方法後
再呼叫 Dispose 方法
並將 Connection 設為 Nothing (或 Null)?答案是不必要的
因為 GC 過一陣子就會自動回收未再被參照的聯機
手動呼叫 Dispose 只不過提早回收的動作而已
而且若是該聯機
可能會在短時間內被大量使用者同時存取的話
也應讓其待在 Pool 中待命
而應避免手動呼叫 Dispose 方法
導致它被真正關閉並被回收
而無法有效地被重復使用
由於 GC 只會在系統閒置或內存不足時才啟動
因此除非是使用頻率非常繁復的資源
否則交由 GC 自行處理即可
而設為 Nothing (或 Null) 也只是將 Connection 變量的位置清除 (Null Reference)
事實上原來 New 出來的 Connection 對象還是存在
而 Dispose 方法是用來處理自行建立的 Windows 資源
但又不會自行釋放的對象
如檔案 (開檔與關文件)
GDI 對象 (直接由 Win API 叫用)…等等
接下來
再回頭探討
NET 的 VB/C# 語言中都有的 using statement
using 語句算是簡易版的 try
finally pattern
可讓程序員以較簡便的寫法盡早去釋放資源
尤其最適用在有限的 unmanaged resources 上
例如
檔案和串流 I/O
Socket 網絡連接
File Handle (檔案控制代碼)
COM 組件
繪圖和字形
數據庫存取
WorkflowRuntime (WF)
…等等的內存自動釋放
using statement 遇到例外時
也會拋出例外 (throw)
但不會去 catch 處理例外
因此若您想要自行處理例外的話
只能回歸傳統的 try
catch
finally 寫法
提供給 using statement 的對象必須實作 IDisposable 接口
若是自己寫的 class
只要實作 System
IDisposable 接口
即擁有 Dispose 方法
之後若引用 using statement 去釋放這個 class 的 instance
即會自動做 object 的 Close()
Dispose()
設定為 null (Nothing) 這三種動作
不需要再自己手動處理
反而若是自己手動多下一次 Close()
會讓 CLR 浪費資源多做一次處理
反倒會影響程序「性能 (performance)」
根據國外網站及 ADO
NET
書籍證實
若 using 語句搭配 CommandBehavior
CloseConnection 一起使用
其重復關閉數據庫聯機的動作
會大幅地降低程序性能
處理時間甚至會多出
% 以上 (叫用 ExecuteReader() 時
若搭配 CommandBehavior 枚舉值 (enumerated value)
可要求在查詢完成後
自動關閉數據庫聯機)
此外
using statement 也可多層巢狀地使用
例如
第一層的 using statement 裡包 SqlConnection 的宣告及 instance 的新增
第二層包 SqlCommand
第三層包 SqlDataReader
您亦可在巢狀的 using statement 中指定多種的系統資源
包括數據庫的 transaction 交易處理
From:http://tw.wingwit.com/Article/program/net/201311/11179.html