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

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.

Related

Dropwizard default connection pooling does not expire connections properly

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

Recover connection after failover as HikariCP doesn't detect DB DNS change

Environment
Hikari CP Version : 3.4.1
JDK version: 1.8.0_251
Database: Azure SQL
SpringBoot Version: 2.2.2 RELEASE
MS-SQL JDBC Driver version:- 8.4.1-jre8
I am working on a Spring Boot app where I have a requirement for configuring the auto failover of database and we are leveraging Azure Failover Groups. The application is connected to the primary database and when the manual failover of the primary server is done, the application should connect to secondary server which is now the new primary.
Below is my JDBC connection string and Hikari properties:
logging.level.org.springframework.jdbc.core=DEBUG
spring.datasource.url=jdbc:sqlserver://<FailoverGroupname>.database.windows.net:1433;database=<DatabaseName>;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
spring.datasource.username=demo
spring.datasource.password=***
spring.datasource.initialization-mode=always
hibernate.hikari.minimumIdle=0
hibernate.hikari.maxPoolSize=1
hibernate.hikari.autoCommit=false
hibernate.hikari.initializationFailTimeout=3000
hibernate.hikari.connectionTestQuery=SELECT 1
When the application is started, below is the analysis:
Hikari has a valid connection in the pool
Spring JPA Transaction pulls the connection from the pool
Data is getting persisted in database successfully
next, Manual Failover is done
txn.begin(), throws exception
Broken Pipe Write Failed Exception
Connection is closed (SQLServerException: The connection is closed)
Connection remains closed till the application is running
Expectation:
Since pool has come in bad state, the connections after getting closed should be recovered and connect to the new primary database that serves as backup
Does anyone knows how can I re-establish the closed connections to auto reconnect to backup database.

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.

Try set initial pool size of database connections (spring-boot)

So, i have a application that uses spring-boot 1.4.0 and a Oracle database. I'm trying to define the number of connections of the pool in the application.properties, using these configs:
spring.datasource.driverClassName = oracle.jdbc.OracleDriver
spring.datasource.url = url
spring.datasource.username = username
spring.datasource.password = password
spring.datasource.maxActive= x
spring.datasource.initialSize= y
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1 from dual
And i'm using the query
select *from V$SESSION where username= 'username';
to check the database connections, but when i run the application it's always using 10 connections, despite what i define as the initialSize. I tried to check other stackoverflow answers and examples on GitHub and i don't know why it's not working, so i would appreciate if someone can help me. Thanks!
Spring Boot 1.4 does not bind the DataSource in the spring.datasource namespace anymore. Each supported connection pool implementations have a dedicated namespace for their respective keys. You are probably looking at older samples.
You first need to identify which connection pool you are using (if you're relying on the starter you should probably get the Tomcat JDBC pool, see spring.datasource.tomcat). Use your IDE to get the list of keys you can use.

Categories