Что вызывает ошибку записи сокета SpringJDBC с сервера MariaDB? - PullRequest
0 голосов
/ 11 сентября 2018

Мой сервер приложений tomcat имеет службу Spring JDBC Template для подключения к локальной базе данных MariaDB.

Я использую библиотеку Spring-Jdbc версии 4.2.3, библиотеку Mariadb-java-client версии 2.0.1 и MariaDB версии 10.1.18.

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

java.net.SocketException: программное обеспечение вызвало прерывание соединения: ошибка записи в сокет

это полный стек

org.springframework.dao.DataAccessResourceFailureException: PreparedStatementCallback; SQL [select exists (select 1 from smartcard where status>=?)]; (conn:13) Could not send query: Software caused connection abort: socket write error; nested exception is java.sql.SQLNonTransientConnectionException: (conn:13) Could not send query: Software caused connection abort: socket write error
    at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:79) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:645) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:680) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:712) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:722) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:790) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:814) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at com.mypackage.dao.SmartcardDao.hasPronte(SmartcardDao.java:83) ~[classes/:?]
    at com.mypackage.smartcard.SmartcardService.isReady(SmartcardService.java:215) ~[classes/:?]
    at com.mypackage.check.CheckService.isReady(CheckService.java:362) ~[classes/:?]
    at com.mypackage.check.CheckService.getPing(CheckService.java:398) ~[classes/:?]
    at com.mypackage.check.CheckService.getPingAuth(CheckService.java:408) ~[classes/:?]
    at com.mypackage.remote.update.UpdateService.sendPing(UpdateService.java:48) ~[classes/:?]
    at com.mypackage.check.CheckService$2.run(CheckService.java:170) [classes/:?]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_131]
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [?:1.8.0_131]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_131]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [?:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]
Caused by: java.sql.SQLNonTransientConnectionException: (conn:13) Could not send query: Software caused connection abort: socket write error
    at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:156) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.getException(ExceptionMapper.java:118) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbStatement.executeExceptionEpilogue(MariaDbStatement.java:229) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeInternal(MariaDbPreparedStatementClient.java:208) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.execute(MariaDbPreparedStatementClient.java:147) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeQuery(MariaDbPreparedStatementClient.java:161) ~[mariadb-java-client-2.0.1.jar:?]
    at sun.reflect.GeneratedMethodAccessor70.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_131]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_131]
    at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114) ~[tomcat-jdbc.jar:?]
    at com.sun.proxy.$Proxy47.executeQuery(Unknown Source) ~[?:?]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:688) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:629) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    ... 19 more
Caused by: java.sql.SQLException: Could not send query: Software caused connection abort: socket write error
    at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.handleIoException(AbstractQueryProtocol.java:1428) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:217) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeInternal(MariaDbPreparedStatementClient.java:203) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.execute(MariaDbPreparedStatementClient.java:147) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeQuery(MariaDbPreparedStatementClient.java:161) ~[mariadb-java-client-2.0.1.jar:?]
    at sun.reflect.GeneratedMethodAccessor70.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_131]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_131]
    at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114) ~[tomcat-jdbc.jar:?]
    at com.sun.proxy.$Proxy47.executeQuery(Unknown Source) ~[?:?]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:688) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:629) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    ... 19 more
Caused by: java.net.SocketException: Software caused connection abort: socket write error
    at java.net.SocketOutputStream.socketWrite0(Native Method) ~[?:1.8.0_131]
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) ~[?:1.8.0_131]
    at java.net.SocketOutputStream.write(SocketOutputStream.java:155) ~[?:1.8.0_131]
    at org.mariadb.jdbc.internal.io.output.StandardPacketOutputStream.flushBuffer(StandardPacketOutputStream.java:101) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.internal.io.output.AbstractPacketOutputStream.flush(AbstractPacketOutputStream.java:157) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:210) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeInternal(MariaDbPreparedStatementClient.java:203) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.execute(MariaDbPreparedStatementClient.java:147) ~[mariadb-java-client-2.0.1.jar:?]
    at org.mariadb.jdbc.MariaDbPreparedStatementClient.executeQuery(MariaDbPreparedStatementClient.java:161) ~[mariadb-java-client-2.0.1.jar:?]
    at sun.reflect.GeneratedMethodAccessor70.invoke(Unknown Source) ~[?:?]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_131]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_131]
    at org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114) ~[tomcat-jdbc.jar:?]
    at com.sun.proxy.$Proxy47.executeQuery(Unknown Source) ~[?:?]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:688) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:629) ~[spring-jdbc-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    ... 19 more

Это свойства объекта DataSource:

org.apache.tomcat.jdbc.pool.DataSource@10a3e2b{ConnectionPool[
 defaultAutoCommit=null;
 defaultReadOnly=null;
 defaultTransactionIsolation=-1;
 defaultCatalog=null;
 driverClassName=org.mariadb.jdbc.Driver;
 maxActive=10;
 maxIdle=5;
 minIdle=2;
 initialSize=5;
 maxWait=30000;
 testOnBorrow=false;
 testOnReturn=false;
 timeBetweenEvictionRunsMillis=5000;
 numTestsPerEvictionRun=0;
 minEvictableIdleTimeMillis=60000;
 testWhileIdle=false;
 testOnConnect=false;
 password=********;
 url=jdbc:mariadb://localhost/mydb?autoReconnect=true&useSSL=false;
 username=myuser;
 validationQuery=null;
 validationQueryTimeout=-1;
 validatorClassName=null;
 validationInterval=3000;
 accessToUnderlyingConnectionAllowed=true;
 removeAbandoned=true;
 removeAbandonedTimeout=60;
 logAbandoned=true;
 connectionProperties=null;
 initSQL=null;
 jdbcInterceptors=null;
 jmxEnabled=true;
 fairQueue=true;
 useEquals=true;
 abandonWhenPercentageFull=0;
 maxAge=0;
 useLock=false;
 dataSource=null;
 dataSourceJNDI=null;
 suspectTimeout=0;
 alternateUsernameAllowed=false;
 commitOnReturn=false;
 rollbackOnReturn=false;
 useDisposableConnectionFacade=true;
 logValidationErrors=false;
 propagateInterruptState=false;
 ignoreExceptionOnPreLoad=false;
 }

Учтите, что компьютер базы данных и компьютер приложения одинаковы, это строка подключения:

jdbc:mariadb://localhost/mydb?autoReconnect=true&useSSL=false

В чем может быть причина? Я сталкивался с этой проблемой как на компьютерах с Windows (Win 10), так и с Linux (Ubuntu 16.04.2 LTS).

1 Ответ

0 голосов
/ 11 сентября 2018

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

Существует явное свойство "autoReconnect", которое было включено в URL-адресе jdbc, и похоже, что оно должно решить все проблемы, верно?Исходное описание autoReconnect для MySQL:

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

( источник )

Акцент мой.Так что это свойство, вероятно, не делает то, что вы думаете, что оно делает.Этот существующий вопрос переполнения стека еще раз подтверждает это.Я не знаю, изменилось ли что-то там в MariaDB, хотя я не могу найти какую-либо конкретную документацию об этом так быстро.

Лучший способ защититься от устаревших соединений в пуле - это разрешить пул соединений.сделайте это за вас, для чего вы можете определить свойства источника данных testOnBorrow , testOnConnect , testOnIdle , как показано в этом существующем ответе .testOnBorrow, вероятно, достаточно.Я процитирую это на тот случай, если ссылка прервется:

spring.datasource.tomcat.testOnBorrow=true 
spring.datasource.tomcat.validationQuery=SELECT 1

Это предполагает умеренно свежую версию Spring Boot, не должно быть сложно перевести это на то, что вы используете Spring.

...