我们已经开发了一个. NET应用程序与Oracle 12c(12.1.0.4)数据库。这是一个旧应用程序的重写,所以数据库本身并不是新的,也没有因为重写而发生太大的变化。新应用程序是一个. NET 6应用程序,具有前端(Blazor WASM,这里不重要)和Web API后端。后端API公开了许多方法,这些方法通常会访问数据库几次,以返回和/或写入一些数据。很标准的东西。
我们使用Oracle Data Provider for. NET(ODP. NET)的托管驱动程序从Oracle版本3.21.61的“Oracle. ManagedDataAccess. Core”Nuget包访问数据库。一个API方法连接到数据库只是为了执行一个查询,或者在某些情况下是几个查询,所以连接是短暂的。这些查询不会处理大量数据,通常只有几行,没有什么大的数据。
我们上周刚刚部署了新的应用程序,取代了旧的应用程序,在几分钟内,我们遇到了严重的连接池问题,迫使我们关闭应用程序并进行调查。打开连接失败,出现错误消息“* Délai d'expiration de la demande de connexion mise en pool *”(对不起,法语,它大致翻译为“Timeout while pooling the opening of the connection”,或类似的东西)。
我们检查了代码,乍一看,我们发现OracleCommand和OracleDataReader对象没有被释放,所以我们修复了这个问题。但OracleConnection已正确释放。尽管如此,它似乎并没有解决这个问题(尽管我们在测试环境中进行了检查,只有我们开发人员访问应用程序)。我们最终在处理连接之前添加了对ClearPool的调用,这对我来说是错误的,因为在我看来,我们基本上关闭了连接池。虽然这很有帮助,但我们仍然在一天后遇到连接失败,这导致我们增加池的大小,从默认的100增加到200,然后增加到250。到目前为止,它似乎保持在250,但这令人担忧。
基本上,根据我的估计,在给定的时刻,我们可能只有几十个用户,他们可能不会在同一时间访问数据库。所以,不是很多。尽管如此,我们还是需要几百个,尽管我们很难清理游泳池。
下面是我们的应用程序中的一个代码示例,它连接到数据库(这是一个更新查询,所以没有数据读取):
using (OracleConnection conn = new(_connectionString))
{
conn.Open();
OracleCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = requete;
retour.NbEnregistrement = cmd.ExecuteNonQuery();
cmd.Dispose();
OracleConnection.ClearPool(conn);
}
这基本上与Oracle's documentation中的示例相似。我们打开一个连接,创建一个命令,使用它,然后释放命令和连接。
看起来连接池不能正常工作,或者至少不是我认为应该的方式。不过,我对池化工作原理的理解可能是错误的。我和负责监控开发数据库的DBA一起做了一些测试,我们可以看到连接确实得到了重用,尽管没有我预期的那么频繁。另一方面,由于我们清除了池,它甚至根本不能重用连接。
会有什么问题呢?为什么连接池没有完成它的工作,特别是在使用率很低的情况下,为什么我们有必要使用ClearPool,这似乎是只应该在不寻常的情况下使用的东西?
1条答案
按热度按时间w8ntj3qf1#
结果发现有一种情况是OracleConnection没有被正确释放。因此,在该上下文中使用的连接不会在连接池中释放,因此连接池迟早会达到限制,无论它被设置得多高。由于这是应用程序中使用最多的部分,它往往发生得很快。
我修好了,现在一切正常。