Заканчивается подключение к БД!

я запускаю Spring / Hibernate, подключаясь к настройке MySQL, используя c3p0 в качестве моего пула соединений. По какой-то странной причине у него заканчиваются соединения, когда система находится под нагрузкой (конечно).

сайт был довольно стабильным, пока мы не начали попадать на новый уровень трафика (более сотни одновременных пользователей). В этот момент БД расплавится (привязать процессор). Мое первое действие было в приложении для повышения производительности за счет обширного кэширования и оптимизации запросов и т. д.

Теперь он будет просто запускать из соединений периодически. Это даже не кажется, что зависит от нагрузки. Больше времени, что заставляет меня думать, что это утечка, но я не могу понять, откуда она может исходить.

    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>

Я также использую аннотации spring для @Transactional, так как я повторно использую мои услуги в коде без веб-интерфейса.

на самом деле здесь есть только два варианта, это не освобождение соединений, когда это сделано. Или болтается по БД, как будто пытается залезть к ней в штаны. Если у кого есть какие идеи буду признателен thx

ПОСЛЕДУЮЩИЕ ДЕЙСТВИЯ: в итоге получается я сливаю соединений за счет использования OpenSessionInViewInterceptor. У меня была spring security в качестве фильтра, поэтому он подключался к БД и никогда не закрывал их. Этот исправить было переместить OpenSessionInViewInterceptor в OpenSessionInViewFilter.

5 ответов


маловероятно, что @Transactional утечки соединений-в противном случае ваш сайт перестанет работать после первых 100 запросов.

но есть еще одна причина, почему это происходит:

возможно, вы установили тайм-аут для "мертвых" соединений, и некоторые запросы занимают больше времени. Это означает, что ваш пул удалил занятое соединение как "мертвое" из пула и запрашивает другое из БД - пока БД не вытащит вилку.

чтобы отладить это, включите ведение журнала для ваш пул соединений, чтобы вы могли видеть, когда он запрашивает новые соединения.


попробуйте включить ведение журнала и установка c3p0.debugUnreturnedConnectionStackTraces свойство true. Также установить c3p0.unreturnedConnectionTimeout к чему-то меньшему, чем ваше среднее время запроса (1 сек?). Тогда любая вещь, которая занимает больше времени, чем тайм-аут журнал трассировки стека. Это позволит вам довольно быстро сузить круг подозреваемых.

Если там нет трассировки стека, это может быть просто, что ваш бассейн слишком мал. Вы сказали 100 одновременных пользователей, но знаете, сколько запросов в секунду это? Если это 100 запросов в во-вторых, у вас есть 20 соединений, тогда каждое выполнение sql должно занять менее 200 мс (20 соединений => 20 секунд работы в секунду настенных часов для выполнения 100 запросов).


независимо от конфигурации для C3P0 (через Hibernate) может иметь ограничение на сам MySQL. Имейте в виду, что по умолчанию максимальное количество подключений к MySQL-это 100! Поэтому, даже если вы скажете C3P0 объединить до 200, 500 или 1000 соединений, это будет недостижимо. Откройте оболочку MySQL, используя:

$ msql -u [user] -p

и введите следующее, Чтобы получить максимальное количество разрешенных подключений:

$ show variables where Variable_name='max_connections';

Если возвращаемое число слишком низко для вашего приложения, подумайте об его изменении (отредактируйте my.cnf-файл, обычно расположенный внутри/etc/ mysql / в системах Linux).


У меня также была эта проблема. Причиной было то, что у пользователя нет грантов для хоста, поскольку запись /etc/hosts была изменена.


У меня тоже была такая проблема и я решил ее установив свойство checkoutTimeout от C3P0 до 0 вместо значения выше 0.

на самом деле у меня было много потоков, ожидающих соединения, и после 10-х, те же erros, что и у вас.

смотрите документ здесь:http://www.mchange.com/projects/c3p0/#checkoutTimeout