为什么在一段时间后,Spring Boot 和 Postgres 的连接会中断?
为什么在一段时间后,Spring Boot 和 Postgres 的连接会中断?
我使用gradle在Spring Boot中运行,使用tomcat-connection-pool连接池。所有标准的spring-boot-tools都在使用中。我在该web服务器上运行了几个soap-webservice。当测试服务器负载时,一切都运行正常。但是,在大约7.5小时不做任何操作之后,出现了以下异常。虽然是一个超时异常,但我试图通过以下方法来防止它发生:\n
- \n
spring.datasource.url=jdbc:postgresql://mydb?autoReconnect=true
- 我对某些语句使用
@transactional
。但是通常我只使用spring-boot的JPA-Repository
。 - 连接由tomcat-connection-pool管理,所以没有空闲连接问题。
- 当我重新启动应用服务器时,一切都会再次正常运行。
\n
\n
\n
\n
\n我的数据库服务器运行在PostgreSQL 9.4.1 on x86_64-unknown-linux-gnu
上,数据库和应用服务器之间没有防火墙。我需要tcp_keep alives吗?\n为什么连接在一段时间后中断,且无法恢复?\n我的应用属性:\n
# # [ 数据库配置部分 ] # spring.jpa.database=POSTGRESQL spring.jpa.show-sql=false hibernate.format_sql=true hibernate.hbm2ddl.auto=validate spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy spring.datasource.platform=postgres spring.database.driverClassName=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://*****:5434/****** spring.datasource.username=***** spring.datasource.password=***** logging.file=*******.log logging.level.=WARNING
\n
\n
2015-09-29 11:58:50.598 INFO 10498 --- [nio-9092-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : 初始化Spring FrameworkServlet 'dispatcherServlet' 2015-09-29 11:58:50.598 INFO 10498 --- [nio-9092-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': 初始化开始 2015-09-29 11:58:50.674 INFO 10498 --- [nio-9092-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': 初始化完成,耗时76毫秒
\n
\n
2015-09-29 19:23:03.777 WARN 10498 --- [ool-3-thread-16] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL错误: 0, SQL状态: 08006 2015-09-29 19:23:03.779 ERROR 10498 --- [ool-3-thread-16] o.h.engine.jdbc.spi.SqlExceptionHelper : 发送到后端时发生I/O错误。 2015-09-29 19:23:03.785 INFO 10498 --- [ool-3-thread-16] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: 释放批处理时仍然包含JDBC语句 2015-09-29 19:23:03.836 ERROR 10498 --- [ool-3-thread-16] o.s.orm.jpa.JpaTransactionManager : 回滚异常覆盖了提交异常 java.net.SocketException: 连接超时 at java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.8.0_25] at java.net.SocketInputStream.read(SocketInputStream.java:150) ~[na:1.8.0_25] at java.net.SocketInputStream.read(SocketInputStream.java:121) ~[na:1.8.0_25] at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:143) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:112) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:71) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.core.PGStream.ReceiveChar(PGStream.java:282) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1718) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] ... 61 common frames omitted 包装器: org.postgresql.util.PSQLException: 发送到后端时发生I/O错误。 at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:201) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:615) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:465) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:411) ~[postgresql-9.4-1202-jdbc41.jar!/:9.4] at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208) ~[hibernate-core-4.3.11.Final.jar!/:4.3.11.Final] ... 57 common frames omitted 包装器: org.hibernate.exception.JDBCConnectionException: 无法执行语句
\n编辑:\n我已经添加了以下内容,并正在进行测试:\n spring.datasource.testOnBorrow=true\n spring.datasource.validationQuery=SELECT 1\n
\n并删除了autoReconnect
。
问题:为什么在一定时间后,Spring Boot和PostgreSQL连接会断开?
解决方法:
根据Yoshida的建议,解决方法非常简单。只需要在配置中添加以下内容:
spring.datasource.validation-query= select 1 spring.datasource.test-on-borrow=true
其中test-on-borrow参数表示在从连接池借用连接之前是否进行验证,默认为true。如果连接验证失败,连接将被从连接池中删除,并尝试借用另一个连接。
validationQuery参数表示在将连接返回给调用者之前用于验证连接的SQL查询。如果指定了validationQuery,则该查询必须是至少返回一行的SQL SELECT语句。如果未指定validationQuery,则将调用isValid()方法进行连接验证。
在这里,我已经尝试过这种方法,但没有显式设置test-on-borrow为true,因为它是默认值。看来必须要显式设置这个参数。
isValid()方法默认实现了连接的测试。具体实现细节请参考Oracle官方文档:docs.oracle.com/en/database/oracle/oracle-database/12.2/jjucp/…