2009-10-12 92 views
5

給出的方法:爲什麼不處理SqlConnection?

internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) 
{ 
    var dataset = new DataSet(); 

    SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb 
          ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"]) 
          : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]); 
    SqlCommand sqlcmd = sqlc.CreateCommand(); 
    sqlcmd.CommandText = commandText; 
    var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc); 
    adapter.Fill(dataset); 


    return dataset; 
} 

爲什麼SQLC(關閉SqlConnection)未設置調用方法超出範圍或SQLC沒有更多引用/關閉後?

編輯1: 即使它包裹在使用,我仍然可以看到使用(我已經連接池關閉)連接:

SELECT DB_NAME(dbid) as 'Database Name', 
COUNT(dbid) as 'Total Connections' 
FROM sys.sysprocesses WITH (nolock) 
WHERE dbid > 0 
GROUP BY dbid 

編輯2: 有一些更多的調試與我從這裏得到的幫助 - 答案是這個人硬編碼連接字符串與池。感謝所有的幫助 - 如果可以的話,我會將所有回覆標記爲答案。

回答

19

C#的垃圾回收具有不確定性,但語言確實提供了資源配置這樣的確定性結構:

using (SqlConnection connection = new SqlConnection(...)) 
{ 
    // ... 
} 

這將創建一個try/finally塊,這將確保連接對象配置不管是什麼發生在該方法中。你真的應該把實現IDisposable的任何類型的實例包裝在這樣的使用塊中,因爲它可以確保負責任的資源管理(像數據庫連接這樣的非託管資源),並且它可以爲你提供確定性的控制。

+0

+1整齊的答案,比我的好。 – 2009-10-12 03:41:26

1

在垃圾收集之後,它會是工作。打開文件流以進行書寫而不關閉它也是一樣。即使代碼超出範圍,它也可能會「鎖定」。

2

因爲c#是一種垃圾回收語言,垃圾回收不是確定性的。事實是,你的sqlconnection 處置。你只是不會選擇何時。

SQL連接是有限的資源,這是很容易您有可能會創建它們的足夠耗盡。把它寫這樣的而不是:

internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) 
{ 
    var dataset = new DataSet(); 

    using (SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb 
          ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"]) 
          : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) 
    using (SqlCommand sqlcmd = sqlc.CreateCommand()) 
    { 
     sqlcmd.CommandText = commandText; 
     var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc); 
     adapter.Fill(dataset); 

    } 
    return dataset; 
} 

雖然在這種情況下,你可能會擺脫它,因爲.Fill() method is a strange beast:

如果的IDbConnection被填充之前關閉被調用時,它被打開以檢索數據和然後關閉。

因此,這意味着數據適配器應該照顧它,如果你從一個封閉的連接開始。我更關心的是你傳遞的sql命令是一個純字符串。您的查詢中必須有用戶參數,這意味着您將這些數據直接連接到命令字符串中。 不要這樣做!改爲使用SqlCommand的參數集合。

1

我相信它與SqlConnection池有關。你可以做什麼,而且我們經常在工作中將整個調用包裝在使用語句中,這導致它調用dispose()方法,hense關閉連接並處理對象

然後,您可以執行類似這取代:


internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase) 
{ 
    var dataset = new DataSet(); 

    using(SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb 
          ? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"]) 
          : new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) { 
     SqlCommand sqlcmd = sqlc.CreateCommand(); 
     sqlcmd.CommandText = commandText; 
     var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc); 
     adapter.Fill(dataset); 


     return dataset; 
    } 
} 

1

我同意這裏的所有答案,加上一個連接可能是一個更廣泛的範圍,而不僅僅是一個方法。當你需要在不同的地方使用現有的連接時,場景會發生一些變化。對於實施IDisposable的所有對象,請務必在完成使用後確保致電Dispose。這是一個很好的做法,所以你最終不會得到垃圾收集器無法決定如何處理它們的未使用的對象。

相關問題