我正在运行一个使用c3p0作为连接池的Spring / Hibernate连接到MySQL安装程序。出于某些奇怪的原因,当系统处于负载状态时(当然),它用尽了连接。
该网站相当稳定,直到我们开始达到新的流量水平(并发用户超过100个)。届时,DB将会崩溃(与CPU挂钩)。我的第一个动作是在应用程序中通过广泛的缓存和查询优化等来提高性能。
现在,它会间歇性地耗尽连接。似乎甚至都不依赖于负载。更多的时间让我觉得这是一个漏洞,但是对于我一生来说,我不知道它的来源。
WARN [2011-03-07 17:19:42,409] [TP-Processor38] (JDBCExceptionReporter.java:100) - SQL Error: 0, SQLState: null ERROR [2011-03-07 17:19:42,409] [TP-Processor38] (JDBCExceptionReporter.java:101) - An attempt by a client to checkout a Connection has timed out. ERROR [2011-03-07 17:19:42,410] [TP-Processor38] (HttpHeadFilter.java:46) - There was a problem passing thru filter:/is-this-guy-crazy-or-just-a-huge-dancing-with-the-stars-fan org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.exception.GenericJDBCException: could not execute query at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:659) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552) at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343) at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109) Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out. at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106) at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:527) at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
这是我的配置:
<bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"> <property name="targetDataSource" ref="rootDataSource" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="mappingLocations" value="classpath:hibernate-mapping.xml" /> <property name="hibernateProperties"> <props> <prop key="hibernate.connection.provider_class">net.sf.hibernate.connection.C3P0ConnectionProvider</prop> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.cache.generate_statistics">true</prop> <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop> <prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop> <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop> <prop key="hibernate.bytecode.use_reflection_optimizer">${hibernate.bytecode.use_reflection_optimizer}</prop> <!--<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>--> <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop> <!--Actually, it seems the following property affects batch size (or explicit per relationship in the mapping)--> <!--<prop key="hibernate.default_batch_fetch_size">${hibernate.jdbc.batch_size}</prop>--> </props> </property> <property name="dataSource" ref="dataSource" /> </bean> <bean id="rootDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialPoolSize" value="20" /> <property name="maxPoolSize" value="200" /> <property name="checkoutTimeout" value="30000" /> <property name="maxStatements" value="180" /> <property name="minPoolSize"> <value>${hibernate.c3p0.minPoolSize}</value> </property> <property name="acquireRetryAttempts"> <value>${hibernate.c3p0.acquireRetryAttempts}</value> </property> <property name="acquireIncrement"> <value>${hibernate.c3p0.acquireIncrement}</value> </property> <property name="idleConnectionTestPeriod"> <value>${hibernate.c3p0.idleConnectionTestPeriod}</value> </property> <property name="maxIdleTime"> <value>${hibernate.c3p0.maxIdleTime}</value> </property> <property name="maxIdleTimeExcessConnections"> <value>${hibernate.c3p0.maxIdleTimeExcessConnections}</value> </property> <property name="maxConnectionAge"> <value>${hibernate.c3p0.maxConnectionAge}</value> </property> <property name="preferredTestQuery"> <value>${hibernate.c3p0.preferredTestQuery}</value> </property> <property name="testConnectionOnCheckin"> <value>${hibernate.c3p0.testConnectionOnCheckin}</value> </property> <property name="numHelperThreads"> <value>${hibernate.c3p0.numHelperThreads}</value> </property> <property name="unreturnedConnectionTimeout"> <value>${hibernate.c3p0.unreturnedConnectionTimeout}</value> </property> <property name="debugUnreturnedConnectionStackTraces"> <value>${hibernate.c3p0.debugUnreturnedConnectionStackTraces}</value> </property> <property name="automaticTestTable"> <value>${hibernate.c3p0.automaticTestTable}</value> </property> </bean> hibernate.c3p0.acquireIncrement=5 hibernate.c3p0.minPoolSize=20 hibernate.c3p0.acquireRetryAttempts=30 hibernate.c3p0.idleConnectionTestPeriod=3600 hibernate.c3p0.maxIdleTime=7200 hibernate.c3p0.maxIdleTimeExcessConnections=1800 hibernate.c3p0.maxConnectionAge=14400 hibernate.c3p0.preferredTestQuery=select 1; hibernate.c3p0.testConnectionOnCheckin=false hibernate.c3p0.numHelperThreads=6 hibernate.c3p0.unreturnedConnectionTimeout=0 hibernate.c3p0.debugUnreturnedConnectionStackTraces=true hibernate.c3p0.automaticTestTable=test_connection;
我正在运行OpenSessionInViewInterceptor,它应该关闭连接:
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> <property name="flushModeName"> <value>FLUSH_AUTO</value> </property> </bean>
我还在@Transactional中使用spring注释,因为我在非Web前端代码中重用了我的服务。
此处实际上只有两个选项,完成后不会释放连接。或者它正在闲逛数据库,就像试图进入她的裤子。如果有人有任何想法,我将不胜感激
跟进: 最终,我发现由于使用OpenSessionInViewInterceptor而导致连接泄漏。我让Spring Security作为过滤器运行,因此它将连接到DB并永远不会关闭它们。解决方法是将OpenSessionInViewInterceptor移至OpenSessionInViewFilter。
@Transactional泄漏连接的可能性很小-否则,您的网站将在前100个请求后停止工作。
@Transactional
但是发生这种情况还有另一个原因:
也许您已为“死”连接设置了超时,并且某些查询花费的时间更长。这意味着您的池从池中删除了繁忙的连接(“死”),并向数据库请求另一个连接- 直到数据库拔掉插头为止。
要调试此功能,请为连接池启用日志记录,以便您可以看到它何时请求新连接。