为什么强制.Close()和使用(...)后,SqlConnection仍然打开?

时间:2018-03-04 01:58:15

标签: c# sql-server sqlconnection

我正在使用ADO.Net和EF进行一些实验,以便更好地了解它如何处理SQL Server连接。

我发现ADO.Net非常有趣。我创建了多个任务,调用一个简单的插入SQL脚本,并正确等待处置SqlConnectionSqlCommand。这里没什么特别的,但是当10k任务完成处理时,所有SQL连接仍然挂起(我通过运行sp_who确认)。清除这些连接的唯一方法是关闭应用程序实例。

怎么可能呢?我尝试了很多东西来强迫它关闭,= null数据访问实例+强制GC但没有......

我试图理解这种行为,但我失败了。有线索吗?

static void Main(string[] args)
{
    Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));

    for (int i = 0; i < 10000; i++)
    {
        Task.Run(() =>
            {
                var dbLegacy = new DataAccessLegacy();
                dbLegacy.TableBInsert();
                dbLegacy = null;
            });
    }

    Console.ReadKey();
}

public void TableBInsert()
{
    using (SqlConnection connection = new SqlConnection(@"Password=qpqp;Persist Security Info=True;User ID=sqlUser2;Initial Catalog=DatabaseA;Data Source=VM2HOSTNAME\VM2INSTANCEA"))
    {
        using (SqlCommand command = new SqlCommand("DatabaseBInsert", connection))
        {
            command.CommandType = CommandType.StoredProcedure;

            command.Parameters.Add("ColAInt", SqlDbType.Int);
            command.Parameters[0].Value = (new Random()).Next(0, 5000);

            command.Parameters.Add("ColBTinyInt", SqlDbType.TinyInt);
            command.Parameters[1].Value = (new Random()).Next(1, 255);

            command.Parameters.Add("ColCVarchar", SqlDbType.VarChar);
            command.Parameters[2].Value = Convert.ToChar((new Random()).Next(1, 255)).ToString();

            command.Parameters.Add("ColDVarcharMax", SqlDbType.VarChar);
            command.Parameters[3].Value = Convert.ToChar((new Random()).Next(1, 255)).ToString();

            command.Parameters.Add("ColEDecimal", SqlDbType.Decimal);
            command.Parameters[4].Value = (new Random()).Next(0, 5000) + 0.5;

            command.Parameters.Add("ColFSmallInt", SqlDbType.SmallInt);
            command.Parameters[5].Value = (new Random()).Next(0, 5000);

            command.Parameters.Add("ColGDateTime", SqlDbType.DateTime);
            command.Parameters[6].Value = DateTime.Now;

            command.Parameters.Add("ColHChar", SqlDbType.Char);
            command.Parameters[7].Value = Convert.ToChar((new Random()).Next(1, 255)).ToString();

            command.Parameters.Add("ColINVarchar", SqlDbType.NVarChar);
            command.Parameters[8].Value = Convert.ToChar((new Random()).Next(1, 255)).ToString();

            command.Parameters.Add("ColJNChar", SqlDbType.NChar);
            command.Parameters[9].Value = Convert.ToChar((new Random()).Next(1, 255)).ToString();

            connection.Open();
            command.ExecuteScalar();
            connection.Close();

            command.Dispose();
        }

        connection.Dispose();
    }
}

1 个答案:

答案 0 :(得分:6)

默认情况下,ADO.Net使用connection pooling。从文档(强调我的):

  

连接池减少了必须打开新连接的次数。 pooler保持物理连接的所有权。它通过为每个给定的连接配置保持一组活动连接来管理连接。每当用户在连接上调用Open时,pooler将在池中查找可用连接。如果池连接可用,则将其返回给调用者,而不是打开新连接。 当应用程序在连接上调用Close时,pooler会将其返回到池化的活动连接集,而不是将其关闭。一旦连接返回到池,就可以在下一个Open调用中重用它。