【问题标题】:jTDS socket hanging with C3P0 connection check (SQL Server 2008 R2)jTDS 套接字挂起与 C3P0 连接检查 (SQL Server 2008 R2)
【发布时间】:2011-08-08 19:35:21
【问题描述】:

这里是环境:

  • Java 5
  • 在 Windows 上的 Tomcat 6.0.18 中运行的 Web 应用程序(不确定版本)
  • 数据库:SQL Server 2008 R2
  • JDBC 驱动程序:jTDS 1.2.5
  • 连接池提供者:C3P0 0.9.1.2

我正在尝试调试客户遇到的问题。基本上每隔几周,我们的 Web 应用程序就会锁定在他们的服务器上,他们无法访问它。重新启动可以解决问题。进一步调查表明,一切都被锁定的原因是一切都在等待数据库连接返回。我认为问题可能出在 SQL Server 上,而不是 C3P0。

我认为 C3P0 的“空闲检查查询”正在挂起。查询是这样的:

select * from c3p0_connection_test_table

看起来这个查询已经运行了,结果永远不会返回。这是我在线程转储中看到的内容。注意DefaultConnectionTester.activeCheckConnection(),这是空闲检查:

"com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2" daemon prio=6 tid=0x0000000007c32000 nid=0x1250 runnable [0x000000001072f000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at java.io.DataInputStream.readFully(DataInputStream.java:178)
    at java.io.DataInputStream.readFully(DataInputStream.java:152)
    at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(SharedSocket.java:841)
    at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(SharedSocket.java:722)
    - locked <0x000000016ac03f48> (a java.util.ArrayList)
    at net.sourceforge.jtds.jdbc.ResponseStream.getPacket(ResponseStream.java:466)
    at net.sourceforge.jtds.jdbc.ResponseStream.read(ResponseStream.java:103)
    at net.sourceforge.jtds.jdbc.ResponseStream.peek(ResponseStream.java:88)
    at net.sourceforge.jtds.jdbc.TdsCore.wait(TdsCore.java:3928)
    at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1045)
    - locked <0x000000016d965268> (a net.sourceforge.jtds.jdbc.TdsCore)
    at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java:465)
    at net.sourceforge.jtds.jdbc.JtdsStatement.executeQuery(JtdsStatement.java:1301)
    at com.mchange.v2.c3p0.impl.DefaultConnectionTester.activeCheckConnection(DefaultConnectionTester.java:73)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.testPooledConnection(C3P0PooledConnectionPool.java:374)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.refurbishIdleResource(C3P0PooledConnectionPool.java:310)
    at com.mchange.v2.resourcepool.BasicResourcePool$AsyncTestIdleResourceTask.run(BasicResourcePool.java:1999)
    at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

但是什么会导致这样一个简单的查询在从套接字读取时挂起?我不相信该表上会有任何数据库锁定,因为它完全由 C3P0 管理并且从未插入/更新。此外,任何从池中获取连接的失败尝试(如果这是挂起的原因),我希望在某个地方有一个堆栈跟踪。相反,我看到的是应用程序刚刚锁定,因为所有未来的连接请求都在等待这个“空闲检查”完成。

这是等待“空闲检查”完成的线程之一:

    "http-80-3" daemon prio=6 tid=0x0000000007c33800 nid=0x122c in Object.wait() [0x000000001082d000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:579)
    - locked <0x0000000167a88a60> (a com.mchange.v2.resourcepool.BasicResourcePool)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
    at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
    at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
    at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
    at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
    at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
    at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:555)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
    at sun.reflect.GeneratedMethodAccessor105.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy15.getTransaction(Unknown Source)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:317)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy79.getCrowdProperties(Unknown Source)
    at com.jamasoftware.contour.gateway.crowd.CrowdSsoServices.autoLogin(Unknown Source)
    at com.jamasoftware.contour.security.AutoLoginServicesManager.autoLogin(Unknown Source)
    at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:74)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:277)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at com.jamasoftware.contour.view.filter.CheckSetupFilter.doFilter(Unknown Source)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.concurrent.ConcurrentSessionFilter.doFilterHttp(ConcurrentSessionFilter.java:99)
    at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at com.jamasoftware.contour.view.filter.ExpirationFilter.doFilter(Unknown Source)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at com.jamasoftware.contour.view.filter.GzipFilter.doFilter(Unknown Source)
    at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
    at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
    at java.lang.Thread.run(Thread.java:619)

从C3P0的源码来看,最上面的两行:

at java.lang.Object.wait(Native Method)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:579)

...仅在连接等待“空闲检查”时发生。

很遗憾,这是一个客户,我无法在这里报告环境的确切细节。但是我可以在下次通话时向他们提出任何建议。

更新:

他们的应用程序今天再次被锁定。以下是我们迄今为止尝试过的事情:

  • 他们已更新到最新的 jTDS 驱动程序 (1.2.5)
  • 我已将连接字符串上的 socketTimeout 属性设置为 300,但驱动程序在 5 分钟后仍停留在 socketRead0() 上
  • 我们将活动检查查询从“select * from c3p0_connection_test_table”更改为“select 1”
  • 我们已将 unreturnedConnectionTimeout 和 debugUnreturnedConnectionStackTraces 属性添加到 C3P0(不过,它们不会捕获断开的连接)

以下是我们设置的所有 C3P0 连接属性:

    <property name="minPoolSize" value="1"/>
    <property name="maxPoolSize" value="30"/>
    <property name="acquireIncrement" value="3"/>
    <property name="automaticTestTable" value="c3p0_connection_test_table"/>
    <property name="idleConnectionTestPeriod" value="30"/>
    <property name="testConnectionOnCheckin" value="true"/>
    <property name="testConnectionOnCheckout" value="true"/>

发生的一件奇怪的事情是,当应用程序被锁定时,我们尝试使用应用程序用户登录 SQL Server Management Studio,但它不让我们进入(我认为这只是一个正常的超时错误) .数据库已启动并侦听端口 1433(使用telnet 验证),因此我认为这意味着已达到与数据库的最大连接数。不过,我不确定这是否有助于确定此问题的原因。

没有成功:

  • This person 遇到操作系统问题,可能是服务器上的 NIC 卡数量问题
  • 下面的回答者指出了旧版本 jTDS 中的一个错误here

有用的答案可以要求我检查客户端计算机上的某些内容,或者指出可能的根本原因。任何有助于我追查的答案都将获得赏金。

【问题讨论】:

    标签: sql-server jdbc c3p0 python-idle jtds


    【解决方案1】:

    第一个想法:检查他们使用的是最新的 jTDS 版本,并且 SQL Server 已修补并更新到最新的 SP!

    在 jTDS 错误跟踪中有一些关于这种行为的报告,最引人注目的是this one。显然 SQL Server 正在关闭连接,但 jTDS 没有注意到。

    在较新版本的 jTDS 中,有一个 socketTimeout property(默认值=0),也许这会有所帮助。

    您还可以测试不同的 JDBC 驱动程序。

    【讨论】:

    • 很好的建议,谢谢。当我很快在这里与他们会面时,我会调查这些问题,并用任何新的细节更新这个问题。
    • 他们正在使用最新的 jTDS (1.2.5),而 SQL Server 似乎是最新 SP (SQL Server 2008 RC2) 的一个相当普通的安装。我让他们添加了 socketTimeout 属性(我们将其设置为极高的 300 或 5 分钟),但他们最终还是再次遇到了这个问题。
    • @SeanA: 1. socketTimeout 的值越高,jTDS 意识到连接断开的时间就越长(loginTimeout 也是如此)。 2. 由于您提到无法使用 Management Studio 进行连接,这让我想知道每个用户配置的最大连接数是多少。 3. RC2 和 R2 一样吗? 4. 你不考虑向M$寻求支持吗? 5.你是本地连接,是不是用localhost服务器地址?
    • 1.我设置了 5 分钟的 socketTimeout,但连接仍然锁定了几个小时。 2. 这也是我的怀疑,我们目前正在调查 SQL Server 配置允许多少连接,以及我们的连接池认为它可以拥有多少连接。 3. 编辑为 R2(我的错误)。 4. 客户可能会升级到微软,但在那之前我会尽我所能。 5. 应用程序使用在其 DNS 中设置的主机名与数据库对话
    • 您是否尝试过使用不带 c3p0 的驱动程序来查看问题是 c3p0 还是某些 sqlserver 设置?也就是说,让应用程序直接使用驱动程序,看看是否会遇到相同的套接字超时问题。
    【解决方案2】:

    在sql server中检查-属性-连接-“使用查询调控器防止长时间运行的查询”是否被禁用

    【讨论】:

      【解决方案3】:

      我在使用 jtds 连接到 sql server 时遇到了 c3p0 (0.9.1) 挂起的类似问题。

      我通过不使用 c3p0 解决了这个问题,只在需要时使用 DriverManager 打开连接。我确信它的性能不高,但它确实有效。

      【讨论】:

        【解决方案4】:

        在测试连接时是否还有另一个线程关闭了连接?看起来 C3P0 在 c3p0-0.9.2-pre3 中修复了这个问题:

        -- 需要对 PooledConnections 进行测试以拥有关联的锁 和那些 PooledConnections 为了防止 PooledConnection.close() 时偶尔出现死锁 与连接测试相吻合。非常感谢匿名 SourceForge 用户 提请注意这个问题。

        来自:https://github.com/swaldman/c3p0/blob/master/src/dist-static/CHANGELOG

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-17
          • 2020-04-12
          • 1970-01-01
          相关资源
          最近更新 更多