我们的应用使用以下连接字符串连接到我们的数据库:
Data Source=<IP>;Initial Catalog=<DBName>;User ID=<Account>;Password=<Password>
它使用它来尝试将数据存储在一个循环中,该循环可以通过遵循伪代码来简化:
bool stored;
do
{
(using)(SqlConnection conn = new SqlConnection(StaticConnectionString))
{
try
{
conn.Open();
//Create SP command and execute here
stored = true;
}
catch(Exception e){/* Log and sleep few secs */}
}
}while(!stored)
由于设计错误,我们遇到了阻塞和极高磁盘I / O的问题。我们将DB置于单用户模式:
ALTER DATABASE <DBName> SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
修复了问题,然后将数据库翻转为MULTI_USER。 之后我们的exe的所有其他实例都重新连接到数据库 - 但是试图插入大量数据的exe(前一个循环在几十个并行线程中运行以用于不同的记录)在此之后的一小时内没有恢复(比我们重新启动)。在尝试连接时,它一直在跟踪异常:
System.Data.SqlClient.SqlException (0x80131904): Cannot open database "<DBName>" requested by the login. The login failed.
Login failed for user '<Account>'.
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at <Our Call to Connection.Open>
ClientConnectionId:9dcf1a45-0f53-4a0f-be8b-63d871ca0afd
所有线程都在为同一个内部连接遇到问题(.NET framweork连接池ClientConnectionId guid在此问题的所有堆栈跟踪中重复)。在TCPView和进程监视器中,我可以清楚地看到应用程序甚至没有尝试创建与服务器的新连接 - 它只是在某种程度上内部记住由于SINGLE_USER模式连接失败并在下次尝试时重新抛出异常,并且池没有尝试清除这样的连接。 我试图强制几个完整的GC - 没有变化,分离附加数据库 - 没有变化;禁止网络访问sql server并重新启用它 - 没有变化。
为什么连接池没有丢失连接失败?我们如何解决这个问题?