DBCP и Hibernate on Spring не повторно открывают мертвые соединения, почему?

Я использую Hibernate и DBCP для управления соединениями mySQL, все в проекте Spring.

Все работает нормально. Единственная проблема заключается в том, что если приложение остается неподвижным в течение длительного времени, оно выдает исключение, потому что соединение разорвано (то же самое, если я перезапущу mySQLd, когда приложение запущено). Это не имеет большого значения, потому что пользователь получит страницу исключения (или пользовательскую), и перезагрузка решит проблему. Но я хотел бы решить ее. Вот часть исключения:

com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception: 

** НАЧАТЬ ВЛОЖЕННОЕ ИСКЛЮЧЕНИЕ **

СООБЩЕНИЕ java.io.EOFException: Не удается прочитать ответ от сервера. Ожидается чтение 4 байтов, чтение 0 байтов перед неожиданной потерей соединения.

ТРАССИРОВКИ СТЕКА:

java.io.EOFException: невозможно прочитать ответ с сервера. Ожидается чтение 4 байтов, чтение 0 байтов перед неожиданной потерей соединения.

Я погуглил и обнаружил, что с mysql я должен установить для свойства dbcp.BasicDataSource testOnBorrow значение true, что я и сделал в своем servlet-context.xml:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://${mySQL.host}/${mySQL.db}" />
    <property name="username" value="${mySQL.user}" />
    <property name="password" value="${mySQL.pass}" />
    <property name="testOnBorrow" value="true"></property>
</bean>

Но проблема сохраняется. Любые подсказки?

Решение! Я использовал:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://${mySQL.host}/${mySQL.db}" />
    <property name="username" value="${mySQL.user}" />
    <property name="password" value="${mySQL.pass}" />
    <property name="testOnBorrow" value="true"></property>
    <property name="validationQuery" value="SELECT 1"></property>
</bean>

person gotch4    schedule 12.04.2011    source источник


Ответы (1)


Если вы установили testOnBorrow, вы также должны установить validationQuery -

validationQuery — SQL-запрос, который будет использоваться для проверки подключений из этого пула перед возвратом их вызывающей стороне. Если указано, этот запрос ДОЛЖЕН быть оператором SQL SELECT, который возвращает хотя бы одну строку.

Я также установил timeBetweenEvictionRunsMillis, чтобы мертвые соединения удалялись из пула.

person Tarlog    schedule 12.04.2011
comment
Означает ли это, что этот запрос будет выполняться каждый раз, когда Hibernate заимствует одно соединение у DBCP??? Не слишком ли это тяжело? - person gotch4; 13.04.2011
comment
Это должен быть крошечный запрос, который выполняется очень быстро. Предполагая, что Hibernate выполняет несколько не крошечных запросов для каждого соединения, еще один крошечный запрос не должен влиять на производительность. - person Tarlog; 13.04.2011
comment
хм.... Да, я вижу, я использовал SELECT 1 (это предлагается на вики dbcp). Во всяком случае, я думаю, что спящий режим будет получать соединение каждый раз, когда он открывает сеанс. Это означает примерно каждый раз, когда контроллер обрабатывает запрос. Я надеюсь, что это просто проблема, связанная с MySQL. - person gotch4; 13.04.2011