バージョンアップ内容
2011年8月9日にマイクロソフトがリリースした.NET Framework4の信頼性に関する更新1(http://support.microsoft.com/kb/2533523)で、本問題の改善が図られています。
基本的に、SqlClientがアプリケーションにプールを返す前に、プールのコネクションが無効化されていないかを確認します。もしコネクションが無効の場合、SqlClientは単純にアプリケーションにコネクションを返す前に再接続処理をします。
この修正は、サーバのラウンドトリップを増やしません。代わりに、TCPレイヤでソケット状態を確認するので、速く効果的です。しかし、この修正は再接続処理の代わりになるわけではありません。特にSQL Azureに接続する場合、再接続処理の実装は、まだ必要なプラクティスとして推奨します。この改善により、SQL ServerとSQL Azureへの接続時に、節奥に失敗する機会を減らしました。
導入背景
SQL Azureに接続した時に、よく遭遇するエラーの一つが、「A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 – An established connection was aborted by the software in your host machine.)」です。このエラーは、SqlClientがプールから無効なコネクションを取得したときに発生し、アプリケーションに返されます。。プール上のコネクションは、ネットワークやSQL Azureで制限されて無効化されます。結果的に、たとえば実行コマンドなどでSqlException例外が発生します。
以下のようなコードを検討しましょう。
try
{
// Let’s assume the connection string uses default connection pool set to true
// and the connection pool was already previously created for this same
// connection string
using (SqlConnection connection = new SqlConnection("…"))
{
// If the connection pool in not empty,
// even if the connection returned above is dead,
// the SqlConnection.Open command below executes succesfully.
connection.Open();
SqlCommand command = new SqlCommand("select product_name from products");
command.Connection = connection;
command.CommandTimeout = 3;
// The Sqlexception gets thrown here,
// when it tries to send the command to SQL Server.
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
…
}
}
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
この例では、Openメソッドがいつでも成功します。アプリケーションからSQL Azureに接続する旅に、再接続処理を追加しています。
情報源
MSDNのBlogに掲載されたMinimizing Connection Pool errors in SQL Azureをざっくり意訳した投稿です。