Dropwizard default connection pooling does not expire connections properly - java

I am using Dropwizard with the Hibernate bundle. After letting it run for some hours/days, any attempt to access the database will result in a
com.mysql.cj.exceptions.CJCommunicationsException: The last packet successfully received from the server was 33.304.281 milliseconds ago. Th
e last packet sent successfully to the server was 33.304.283 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should
consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeout
s, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
[...]
Causing: java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.
The config looks something like this:
database:
# the name of your JDBC driver
driverClass: com.mysql.cj.jdbc.Driver
# the username
user: ...
# the password
password: ...
# the JDBC URL
url: jdbc:mysql://localhost/my_database
# any properties specific to your JDBC driver:
properties:
charSet: utf8mb4
hibernate.hbm2ddl.auto: update
# the maximum amount of time to wait on an empty pool before throwing an exception
maxWaitForConnection: 1s
# the SQL query to run when validating a connection s liveness
validationQuery: "/* MyService Health Check */ SELECT 1"
# the timeout before a connection validation queries fail
validationQueryTimeout: 3s
# the minimum number of connections to keep open
minSize: 8
# the maximum number of connections to keep open
maxSize: 32
# whether or not idle connections should be validated
checkConnectionWhileIdle: true
checkConnectionOnBorrow: true
# the amount of time to sleep between runs of the idle connection validation, abandoned cleaner and idle pool resizing
evictionInterval: 10s
# the minimum amount of time an connection must sit idle in the pool before it is eligible for eviction
minIdleTime: 1 minute
maxConnectionAge: 14400s
The hibernate bundle is instantiated from the configuration just like in the DW docs: https://www.dropwizard.io/en/latest/manual/hibernate.html#configuration
The DB wait_timeout is 28800s. I don't understand how the connections do not get either removed due to old age (the time since last package suggested by the error messages is greater than 14400s) or after validation because of
checkConnectionOnBorrow: true
dropwizard Version: 2.0.18
mysql-connector-java Version: 8.0.23
I am out of ideas on how to approach this please help.

The problem should be fixed if you change the database.url property to contain autoReconnect=true.
So in your configuration put:
database:
url: jdbc:mysql://localhost/my_database?autoReconnect=true
In documentation of Connector/J:
autoReconnect
Should the driver try to re-establish stale and/or dead connections?
If enabled the driver will throw an exception for queries issued on a
stale or dead connection, which belong to the current transaction, but
will attempt reconnect before the next query issued on the connection
in a new transaction. The use of this feature is not recommended,
because it has side effects related to session state and data
consistency when applications don't handle SQLExceptions properly, and
is only designed to be used when you are unable to configure your
application to handle SQLExceptions resulting from dead and stale
connections properly. Alternatively, as a last option, investigate
setting the MySQL server variable 'wait_timeout' to a high value,
rather than the default of 8 hours.
Reference: https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-high-availability-and-clustering.html

Related

How to make Spring server to start even if database is down?

I'm using a Spring Boot(1.4.7) & MyBatis.
spring.main1.datasource.url=jdbc:mariadb://192.168.0.11:3306/testdb?useUnicode=true&characterEncoding=utf8&autoReconnect=true&socketTimeout=5000&connectTimeout=3000
spring.main1.datasource.username=username
spring.main1.datasource.password=password
spring.main1.datasource.driverClassName=org.mariadb.jdbc.Driver
spring.main1.datasource.tomcat.test-on-borrow=true
spring.main1.datasource.tomcat.test-while-idle=true
spring.main1.datasource.tomcat.validation-query=SELECT 1
spring.main1.datasource.tomcat.validation-query-timeout=5000
spring.main1.datasource.tomcat.validation-interval=5000
spring.main1.datasource.tomcat.max-wait=5000
spring.main1.datasource.continue-on-error=true
I cannot start program with errors when database is disconnected on Eclipse or Linux server.
(Database is not located on localhost.)
When I try to start program with disconnected database,
print this.
java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=192.168.0.11)(port=3306)(type=master) : connect timed out
Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=192.168.0.11)(port=3306)(type=master) : connect timed out
Stopping service [Tomcat]
Application startup failed
Is there any way?
Thanks
You can set:
spring.sql.init.continue-on-error=true
in your application.properties.
According to the Spring Boot 2.5.5 user guide:
By default, Spring Boot enables the fail-fast feature of its script-based database initializer. This means that, if the scripts cause exceptions, the application fails to start. You can tune that behavior by setting spring.sql.init.continue-on-error.
P.S.: Before Spring Boot 2.5, the property was named spring.datasource.continue-on-error.
I was able to solve this. One main difference between what I got working and the code in the question, though, is that I'm using Hikari instead of Tomcat for the connection pool.
These were the key settings I had to make:
spring.datasource.hikari.minimum-idle: 0
spring.datasource.hikari.initialization-fail-timeout: -1
spring.datasource.continue-on-error: true
spring.datasource.driver-class-name: org.postgresql.Driver
spring.jpa.database-platform: org.hibernate.dialect.PostgreSQLDialect
Setting minimum-idle to 0 allows Hikari to be happy without any connections.
The initialization-fail-timeout setting of -1 tells Hikari that I don't want it to get a connection when the pool fires up.
From the HikariCP documentation:
A value less than zero will bypass any initial connection attempt, and the pool will start immediately while trying to obtain connections in the background. Consequently, later efforts to obtain a connection may fail.
The continue-on-error setting true allows the service to continue even when encountering an error.
Both the driver-class-name and database-platform were required. Otherwise, Hikari tries to figure out those values by connecting to the database (during startup).
Just in case I'm missing something, though, here's my full Spring config:
spring:
application:
name: <redacted>
datasource:
url: <redacted>
username: <redacted>
password: <redacted>
driver-class-name: org.postgresql.Driver
hikari:
minimum-idle: 0
maximum-pool-size: 15
connection-timeout: 10000 #10s
idle-timeout: 300000 #5m
max-lifetime: 600000 #10m
initialization-fail-timeout: -1
validation-timeout: 1000 #1s
continue-on-error: true
jpa:
open-in-view: false
database-platform: org.hibernate.dialect.PostgreSQLDialect
And my project has the following Spring Boot dependencies:
org.springframework.boot:spring-boot
org.springframework.boot:spring-boot-actuator
org.springframework.boot:spring-boot-actuator-autoconfigure
org.springframework.boot:spring-boot-autoconfigure
org.springframework.boot:spring-boot-configuration-processor
org.springframework.boot:spring-boot-devtools
org.springframework.boot:spring-boot-starter
org.springframework.boot:spring-boot-starter-actuator
org.springframework.boot:spring-boot-starter-jdbc
org.springframework.boot:spring-boot-starter-jooq
org.springframework.boot:spring-boot-starter-json
org.springframework.boot:spring-boot-starter-logging
org.springframework.boot:spring-boot-starter-security
org.springframework.boot:spring-boot-starter-test
org.springframework.boot:spring-boot-starter-tomcat
org.springframework.boot:spring-boot-starter-validation
org.springframework.boot:spring-boot-starter-web
You need to add
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
in order to make it works
If the tips above didn't help and you use jpa, then set
spring.jpa.hibernate.ddl-auto=none
it worked for me.
When you build your app you can add that
mvn clean install -DskipTests
it will skip the tests of database connection
(-D is used to define a system property)

mysql db connection lost [duplicate]

I have an app that uses spring-boot,jpa-hiberanate with mysql.I am getting this error log
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 56,006,037 milliseconds ago. The last packet sent successfully to the server was 56,006,037 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
Here is my application.properties
# DataSource settings: set here configurations for the database connection
spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = test
spring.datasource.password = test
spring.datasource.driverClassName = com.mysql.jdbc.Driver
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate settings are prefixed with spring.jpa.hibernate.*
spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy
To solve this issue I can use
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1
But I checked that it's not recommended .So can anyone suggest me what should I do to overcome this error
The easiest way is to specify the autoReconnect property in the JDBC url, although this isn't the recommended approach.
spring.datasource.url = jdbc:mysql://localhost:3306/test?autoReconnect=true
This can give issues when you have an active connection and during a transaction something happens and a reconnect is going to happen. It will not give issues when the connection is validated at the start of the transaction and a new connection is acquired at the start.
However it is probably better to enable validation of your connections during the lifetime of your application. For this you can specify several properties.
First start by specifying maximum number of connections you allow for the pool. (For a read on determining the max poolsize read this).
spring.datasource.max-active=10
You also might want to specify the number of initial connections
spring.datasource.initial-size=5
Next you want to specify the min and max number of idle connections.
spring.datasource.max-idle=5
spring.datasource.min-idle=1
To validate connection you need to specify a validation-query and when to validate. As you want to validate periodically, instead of when a connection is retrieved from the pool (this to prevent broken connections in your pool).
spring.datasource.test-while-idle=true
spring.datasource.test-on-borrow=true
spring.datasource.validation-query=SELECT 1
NOTE: The usage of a validation-query is actually discouraged with as JDBC4 has a better/different way of doing connection validation. HikariCP will automatically call the JDBC validation method when available.
Now that you are also validating while a connection is idle you need to specify how often you want to run this query for the connections and when a connection is considered idle.
spring.datasource.time-between-eviction-runs-millis=5000 (this is the default)
spring.datasource.min-evictable-idle-time-millis=60000 (this is also default)
This all should trigger validation of your (idle) connections and when an exception occurs or the idle period has passed your connections will be removed from the pool.
Assuming you are using Tomcat JDBC as the connection pool this is a nice read of what and how to configure.
UPDATE: Spring Boot 2.x switched the default connection pool to HikariCP instead of Tomcat JDBC.

How to overcome org.springframework.dao.RecoverableDataAccessException?

I keep receiving connectivity issues when connecting my Spring project to a MySQL server. I have tried various tricks that I have found online but to no avail. I need help in order to escape this quandary. I'm placing my Spring settings below and the stack trace as well.
Spring Settings
spring.datasource.tomcat.initialize=true
spring.dataSource.tomcat.url=jdbc:mysql://nope/canttellyou?
autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
spring.dataSource.tomcat.username=nope
spring.dataSource.tomcat.password=sorry
spring.dataSource.tomcat.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.log-validation-errors=true
StackTrace
stackTrace: org.springframework.dao.RecoverableDataAccessException:
PreparedStatementCallback; SQL [select catname from animals]; The last
packet successfully received from the server was 52,962,310
milliseconds ago. The last packet sent successfully to the server was
52,962,310 milliseconds ago. is longer than the server configured value
of 'wait_timeout'. You should consider either expiring and/or testing
connection validity before use in your application, increasing the
server configured values for client timeouts, or using the Connector/J
connection property 'autoReconnect=true' to avoid this problem.; nested
exception is com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
The last packet successfully received from the server was 52,962,310
milliseconds ago. The last packet sent successfully to the server was
52,962,310 milliseconds ago. is longer than the server configured value
of 'wait_timeout'. You should consider either expiring and/or testing
connection validity before use in your application, increasing the
server configured values for client timeouts, or using the Connector/J
connection property 'autoReconnect=true' to avoid this problem.
I've been having the same problem. I think the configuration setting we want to turn on is:
testWhileIdle
Here's the related tomcat connection pool docs
I won't know until tomorrow whether or not this worked for me.

Connection to Db dies after >4<24 in spring-boot jpa hibernate

I have an app that uses spring-boot,jpa-hiberanate with mysql.I am getting this error log
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 56,006,037 milliseconds ago. The last packet sent successfully to the server was 56,006,037 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
Here is my application.properties
# DataSource settings: set here configurations for the database connection
spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = test
spring.datasource.password = test
spring.datasource.driverClassName = com.mysql.jdbc.Driver
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate settings are prefixed with spring.jpa.hibernate.*
spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy
To solve this issue I can use
spring.datasource.testOnBorrow=true
spring.datasource.validationQuery=SELECT 1
But I checked that it's not recommended .So can anyone suggest me what should I do to overcome this error
The easiest way is to specify the autoReconnect property in the JDBC url, although this isn't the recommended approach.
spring.datasource.url = jdbc:mysql://localhost:3306/test?autoReconnect=true
This can give issues when you have an active connection and during a transaction something happens and a reconnect is going to happen. It will not give issues when the connection is validated at the start of the transaction and a new connection is acquired at the start.
However it is probably better to enable validation of your connections during the lifetime of your application. For this you can specify several properties.
First start by specifying maximum number of connections you allow for the pool. (For a read on determining the max poolsize read this).
spring.datasource.max-active=10
You also might want to specify the number of initial connections
spring.datasource.initial-size=5
Next you want to specify the min and max number of idle connections.
spring.datasource.max-idle=5
spring.datasource.min-idle=1
To validate connection you need to specify a validation-query and when to validate. As you want to validate periodically, instead of when a connection is retrieved from the pool (this to prevent broken connections in your pool).
spring.datasource.test-while-idle=true
spring.datasource.test-on-borrow=true
spring.datasource.validation-query=SELECT 1
NOTE: The usage of a validation-query is actually discouraged with as JDBC4 has a better/different way of doing connection validation. HikariCP will automatically call the JDBC validation method when available.
Now that you are also validating while a connection is idle you need to specify how often you want to run this query for the connections and when a connection is considered idle.
spring.datasource.time-between-eviction-runs-millis=5000 (this is the default)
spring.datasource.min-evictable-idle-time-millis=60000 (this is also default)
This all should trigger validation of your (idle) connections and when an exception occurs or the idle period has passed your connections will be removed from the pool.
Assuming you are using Tomcat JDBC as the connection pool this is a nice read of what and how to configure.
UPDATE: Spring Boot 2.x switched the default connection pool to HikariCP instead of Tomcat JDBC.

(Enterprise GlassFish v3 build 11) Communication link problem (MySQL DB)

I get a communication link failure while application tries to establish a connection with DB.
[#|2010-04-08T20:09:57.825+0300|SEVERE|glassfish3.0|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=24;_ThreadName=Thread-1;|Cannot connect to database server = com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.|#]
Precisely at this string:
Statement s = conn.createStatement();
where conn is defined as follows:
private static java.sql.Connection conn;
For this app I have set a connection pool with default parameters and currently it (app) uses both JPA and direct JDBC queries. Recreation of connection pool gave nothing, connection pool ping gave next message:
Ping Connection Pool for pool is Failed. Ping failed Exce
ption - Connection could not be allocated because: Communications lin
k failure%%%EOL%%%%%%EOL%%%The last packet sent successfully to the s
erver was 0 milliseconds ago. The driver has not received any packets
from the server. Please check the server.log for more details.%%%EOL
%%%Ping failed Exception - Connection could not be allocated because:
Communications link failure
and flushing the connection pool gave:
com.sun.enterprise.admin.cli.CommandException: remote failure: Failed to flush connection pool ...
However I can connect to the database from a terminal. Besides I have the same app working on my local machine with identical connection pool settings.
Any one has an idea on whats going on or how to solve the trouble?
Such problem could be if you have mysql server & glassfish server on the same host, and in mysql configuration you have option bind to some public address (for example 192.168.0.1 of eth0 interface) that normally successfully working with simple jdbc/jpa using user#localhost, but they don`t in a case of glassfish JTA, instead to bind to some of local address you getting link failure. As rule you could not bind to any local (localhost/127.0.0.1) addresses of such mysql host if public address presented.
Example:
my.cnf
bind-address = 127.0.0.1
bind-address = 192.168.0.1
127.0.0.1 - assign to lo interface
192.168.0.1 - assign to eth0 interface
It is glassfish-mysql bug.
Currently in order to use JTA, you should not bind mysql to such address. (remove "bind-address=192.168.0.1" from my.cnf). Or use user#192.168.0.1 what is less secure.
Besides I have the same app working on my local machine with identical connection pool settings.
Are you connecting to the same database? If yes, maybe check that you're using the same JDBC driver.
In my case I set :
URL : jdbc:mysql://10.81.35.66:3306/testDB
and
url : jdbc:mysql://10.81.31.76:3306/vectordb
both When setting values while creating connection pool in additional property part
on glass fish admin console .

Categories