ODP.NET:使用连接池避免连接超时

9
在一个站点上,我可以使用SQL Developer连接Oracle数据库,让它闲置很长一段时间(例如,>60分钟),然后返回,一切正常。在第二个站点,如果它闲置超过5-10分钟(我没有准确计算),它会使SQL Developer处于一种状态,新操作将超时,并且我需要手动“断开”然后重新连接才能做任何有用的事情。这似乎是第二个站点的连接超时问题,我不知道是什么原因引起的(我想知道如何关闭它,尽管这不是我的主要问题)。
我的程序使用ODP.NET处理间歇性到来的数据。每30分钟(为了讨论),它将获得一堆需要重复连接的数据。它还使用连接池。我已将连接池设置为使用5分钟的生命周期。
我在第二个站点看到的情况(而不是第一个站点)是,我的程序会在每个数据突发开始时收到连接超时异常(例如,ORA-03113)。我认为正在发生的是,在数据突发期间,连接池按设计使用。在突发结束时,“连接生命周期”被检查,而连接并不太旧,因此留在连接池中。然后,30分钟后当新数据到达时,连接被从池中取出(不检查寿命或超时)并被使用,并超时,就像我在SQL Developer中看到的那样。
如何避免连接超时但仍然利用连接池进行突发处理?从文档(和我的经验)来看,连接只在进入池时检查寿命,而不是在出池时检查。

我对这些问题不够了解,但我们曾经遇到过非常类似的问题(更换数据中心)。新的数据中心会关闭任何长时间没有活动的端口(我们在SQL Developer和其他长时间运行的进程中遇到了与您完全相同的问题)。我们向托管公司提出异议,他们最终没有关闭ora端口(但他们傲慢地建议我们为ora连接实现脉冲,这被直接拒绝),但这需要他们付出努力。祝你好运! - Harrison
4个回答

4
这是一个非常老的问题,但我最近使用某个应用程序时遇到了类似的问题,因此我认为其中一些信息可能会对其他人有所帮助。

简而言之,ODP.NET驱动程序和.NET实现之间不兼容,因此您平常使用的连接池设置似乎不能按照您的预期正常工作。

  • 连接的寿命(Connection Lifetime)是主要的问题。我不确定这篇博客是否仍然适用,因为它相当老旧,但我还没有找到任何文件来反驳它,并且它似乎验证了我看到的行为。根据这篇文章,Connection Lifetime确实会像预期那样杀死旧会话,但是只有在对数据库进行调用时才会检查此参数。换句话说,长时间运行的空闲会话永远不会被.NET终止。
  • 如果您在Oracle用户配置文件中将设置为一个值(而不是),那么最终这些长时间运行的空闲参数将被数据库SNIPED。这可能会在.NET方面引起问题,因为除非您明确地检查连接是否仍然打开,否则.NET将提供这些SNIPED连接,就好像它们仍然可用(从而引发上述超时ORA错误)。
  • 解决此问题的诀窍是确保在连接字符串中具有Data Validation=True;。这可以确保.NET在将连接提供给下一个服务调用之前检查会话连接性。当这个验证看到一个SNIPED会话时,它会将其从.NET连接池中移除。
鉴于这些信息,最有可能的是OP最初的问题只出现在一个站点中,原因可能是不同的数据库设置和/或.NET对数据库的调用频率。他可能在两个环境中都遇到了这个问题,但如果一个环境中的用户调用频率足够频繁,以至于“连接生存时间”可以发挥作用,那么他在那个数据库中就永远不会看到这些超时。

现在我仍然没有弄清楚如何在.NET中杀死空闲连接,以防止任何Oracle IDLE_TIME的发生,但只要使用那个“Data Validation = True”参数,您就有希望解决这个问题。


1
如果5分钟的生存时间设置在第一个站点中表现良好,那么我认为这可能是由于某人在Oracle服务器端的配置文件中设置了闲置会话超时。然而,使用5分钟的生存时间设置时,当您的突发量变大时,仍可能会遇到超时问题,因为当您在下一个突发中将连接返回到池中时,它们将被销毁。池将忙于创建和删除连接,并在负载真正大时可能导致连接超时。

0

ODP.NET 默认创建并保持一个连接池中的1个连接处于打开状态。Oracle 服务器可以配置一种服务器端连接超时,该连接将在一段时间后关闭空闲连接。如果您的应用程序长时间空闲,则可能会出现问题,因为当服务器自己关闭连接时,ODP.NET 客户端不知道该连接已关闭。客户端仍然在池中拥有该连接,并将尝试使用它,然后您将收到错误。

有两种解决方案。

  1. 在使用 ODP.NET 连接池时,请勿为连接设置服务器端空闲超时。如果您正在使用连接池,则让服务器放弃空闲连接实际上没有多大意义。
  2. 如果无法执行第 1 步,则可以使用 ODP.NET 连接设置来设置 MinPoolSize=0。MinPoolSize=0 意味着当应用程序空闲时,ODP.NET 客户端将使池中的连接数降为0。当应用程序需要再次执行工作时,这可能会影响性能,因为它将没有可用的连接来处理初始请求,并且必须打开一个连接。但是,如果您的应用程序在长时间空闲期间进行大量工作,则这样做可能是有意义的。

-1
您可以通过将OracleCommand.ConnectionTimeout属性设置为0来指定无限超时。 在这种情况下,将不会有超时(至少在客户端上)。
在此情况下也使用了连接池。

谢谢Tony,但我相信这个设置告诉Oracle等待响应的时间。我遇到的问题是连接进入了一个永远不会得到响应的状态。因此,这个设置可以避免异常,但我的程序仍然无法获得响应 - 所以我不认为这是一个解决方案。 - Andy Jacobs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接