私はここでレガシーコードを扱っていますがSqlDataReader
、閉じられたり破棄されたりすることのないインスタンスがたくさんあります。接続は閉じられていますが、リーダーを手動で管理する必要があるかどうかはわかりません。
これによりパフォーマンスが低下する可能性はありますか?
回答:
次のようなリーダーの使用は避けてください。
SqlConnection connection = new SqlConnection("connection string");
SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection);
SqlDataReader reader = cmd.ExecuteReader();
connection.Open();
if (reader != null)
{
while (reader.Read())
{
//do something
}
}
reader.Close(); // <- too easy to forget
reader.Dispose(); // <- too easy to forget
connection.Close(); // <- too easy to forget
代わりに、ステートメントを使用してそれらをラップします。
using(SqlConnection connection = new SqlConnection("connection string"))
{
connection.Open();
using(SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
//do something
}
}
} // reader closed and disposed up here
} // command disposed here
} //connection closed and disposed here
usingステートメントは、オブジェクトの正しい廃棄とリソースの解放を保証します。
忘れた場合は、ガベージコレクタにクリーニングを任せます。これには時間がかかる場合があります。
SqlCommand.ExecuteReader()を使用してインスタンス化されたSqlDataReaderを破棄しても、基になる接続は閉じられない / 破棄されないことに注意してください。
2つの一般的なパターンがあります。最初に、リーダーは接続の範囲内で開かれ、閉じられます。
using(SqlConnection connection = ...)
{
connection.Open();
...
using(SqlCommand command = ...)
{
using(SqlDataReader reader = command.ExecuteReader())
{
... do your stuff ...
} // reader is closed/disposed here
} // command is closed/disposed here
} // connection is closed/disposed here
データアクセスメソッドが接続を開いてリーダーを返すと便利な場合があります。この場合、返されたリーダーをCommandBehavior.CloseConnectionを使用して開くことが重要です。これにより、リーダーを閉じる/破棄すると、基になる接続が閉じます。パターンは次のようになります。
public SqlDataReader ExecuteReader(string commandText)
{
SqlConnection connection = new SqlConnection(...);
try
{
connection.Open();
using(SqlCommand command = new SqlCommand(commandText, connection))
{
return command.ExecuteReader(CommandBehavior.CloseConnection);
}
}
catch
{
// Close connection before rethrowing
connection.Close();
throw;
}
}
そして呼び出し側のコードは単にリーダーをこのように破棄する必要があります:
using(SqlDataReader reader = ExecuteReader(...))
{
... do your stuff ...
} // reader and connection are closed here.
using
sの使用に耐えられない場合は、finally {}
キャッチ後にブロックでdisposeを呼び出します。これが書かれている方法では、成功したコマンドは決して閉じられたり破棄されたりしません。
安全のために、すべてのSqlDataReaderオブジェクトをusingステートメントでラップします。