我正在使用ADO.Net和EF进行一些实验,以便更好地了解它如何处理SQL Server连接。
我发现ADO.Net非常有趣。我创建了多个任务,调用一个简单的插入SQL脚本,并正确等待处置SqlConnection
和SqlCommand
。这里没什么特别的,但是当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();
}
}
答案 0 :(得分:6)
默认情况下,ADO.Net使用connection pooling。从文档(强调我的):
连接池减少了必须打开新连接的次数。 pooler保持物理连接的所有权。它通过为每个给定的连接配置保持一组活动连接来管理连接。每当用户在连接上调用Open时,pooler将在池中查找可用连接。如果池连接可用,则将其返回给调用者,而不是打开新连接。 当应用程序在连接上调用Close时,pooler会将其返回到池化的活动连接集,而不是将其关闭。一旦连接返回到池,就可以在下一个Open调用中重用它。