背景
我们有一个C#/VB.net客户端应用程序,它使用连接到Oracle数据库的WCF服务。web服务使用.NET框架的Oracle数据提供程序连接到数据库(不要与ODP混淆)。我们的测试人员经历了零星的Oracle帐户锁定,这似乎是在更改用户的Oracle密码后不久发生的。dba_audit_trail日志揭示了在没有任何用户或客户活动的情况下,似乎每隔两分钟就进行一次自动连接的尝试。许多日志(IIS、WCF跟踪、消息记录等)已确认这些连接尝试不是由客户端应用程序直接发起的;它们必须独立于web服务或System.Data.OracleClient库中。自动尝试将永远持续下去,直到web服务的辅助进程(单个工作人员)因不活动而死亡。
在某些情况下,这些自动尝试是在密码更改之前开始的,它们成功地连接到数据库,但一旦密码更改,下一次尝试将失败,导致用户名/密码无效。经过三次尝试,该帐户将被锁定。我们正试图找到这些周期性连接尝试的来源。
我在甲骨文的论坛这里上发现了一个类似的问题,但没有得到解答。
当前思想
我们最近的调查让我们相信,这是来自连接池的意外行为。如果用户在密码更改之前连接到web服务,则将为原始连接字符串创建连接池。在更改密码并重新登录到web服务之后,数据提供程序将根据新的连接字符串创建一个新的连接池。
数据提供程序内部是否有什么东西试图将旧连接从第一个连接池中保存下来?也许第一个连接池正在丢弃旧连接,并试图用一个新连接(现在无效的连接字符串)来补充它。是什么导致的?注意:我们使用的是最小/最大池大小(0/100)的默认设置。
我们不认为我们的代码直接试图从第一个连接池访问连接。用户的会话没有上一次会话密码的任何内存,因此不会使用旧的连接字符串引用第一个连接池。此外,代码中没有任何内容能够解释我们所看到的非常精确的连接间隔。
发布于 2012-10-15 21:50:41
根本的问题最终是未释放的数据库连接。打开连接时,它将从连接池中签出。如果连接从未关闭,则池认为它仍在被使用。这将导致池管理逻辑使用原始连接字符串定期与数据库重新身份验证。当密码更改时,这会很快导致登录尝试失败和帐户锁定。
// Problem logic; connection is never closed/returned to the connection pool.
public static void ConnPoolTest1()
{
OracleConnection conn = new OracleConnection(connectionStringWithPooling);
conn.Open();
//...Do some work
// Sit on this line for 5-10 minutes and examine Oracle's dba_audit_trail.
Console.ReadKey(); // Since connection was never released back to the connection pool, the
// data provider's pool management will regularly re-authenticate with DB.
// If user's password changes before this process dies (releasing the
// connection pools), you start accumulating failed password attempts.
}这个问题的正确解决方法是确保连接在您完成连接时总是返回到池中!
// Best practice: ALWAYS CLOSE YOUR CONNECTIONS WHEN YOU ARE DONE!
public static void ConnPoolTest2()
{
OracleConnection conn = new OracleConnection(connectionStringWithPooling);
conn.Open();
//...Do some work
conn.Close();
// Sit on this line for 5-10 minutes and examine Oracle's dba_audit_trail.
Console.ReadKey(); // No problem here! No recurring authentication attempts because the
// connection has been returned to the pool.
}注意:其他答案建议在密码更改时关闭池并清除旧连接池。在我们搜索未释放的资源时,这些建议为我们提供了一个临时补丁,它们极大地帮助我们孤立了问题。
发布于 2012-10-14 13:10:10
这可能会有一点帮助。
和
OLE、ODBC和Oracle连接池
基本上,在那里的第二个网页中,MSDN声明“一旦创建了连接池,在活动进程结束之前不会被销毁”。您的web服务似乎持有如此多的连接/连接池,因此出现了一些问题。
因此,我的建议是:除了对可能添加的连接日志(可能只是一个文本文件)进行更多的故障排除之外,或者第一个链接有一个很好的命令来跟踪到数据库的连接,我现在会尝试关闭连接池。您所遇到的问题称为“池碎片”。这是连接池中连接所有数据库连接的单一计算机的大量通信量。最终会出现如此多的池,以致于内存问题开始发生,并且连接无法正常关闭。第二个问题将是您的问题,如果连接未关闭,或者假设您的密码更改命令在使用旧连接池的其他命令列表之前执行,则会出现问题。
最终,在您的情况下,您将有一个点(web服务)创建自己的web连接池(而不是为用户),并通过自己的连接将数据返回给用户。这意味着必须有不同类型的身份验证,由web服务端处理,以处理连接的用户。我相信这在你的模型中可能会有太多的改变,但是我强烈建议在最后找到那个解决方案。
发布于 2012-10-15 06:23:17
每当发生任何会使连接失效的事件时,您都需要销毁池,以便对泄漏的连接和/或保持池的活动进行适当标记,以防止重复使用。为此,您需要使用数据提供程序的clearpool或clearallpools方法。
http://msdn.microsoft.com/en-us/library/system.data.oracleclient.oracleconnection.clearpool.aspx
此外,全局异常管理器可以侦听为无效用户引发的异常,并通过枚举标识为连接字符串一部分的用户的连接来销毁该池。也许效率不高,但应该能完成任务。
https://stackoverflow.com/questions/12877042
复制相似问题