I examined related questions here on this topic, and also googled for some time. Still seems I don't understand something crytical in Tomcat's DBCP configuration or mechanics.
I got Tomcat 6, DBCP resource configured in server.xml:
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://myhost:3306/mydb?autoReconnectForPools=true&useUnicode=true"
username="user"
password="password"
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="10000" minEvictableIdleTimeMillis="60000"
maxActive="20" maxWait="20000" maxIdle="10"
removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" />
Also I looked for mysql's wait_timeout and it is default 28800.
In summary I tried several options, but seems the problem is that mysql connections hit 28800 seconds of being idle and server closes them. I thought that pool should somehow handle this situation with validationQuery and testOnBorrow, but seems I'm wrong.
If I use autoReconnect in url after idle period My first query attempt results in "...CommunicationsException: The last packet successfully received from the server was 157,493,261 milliseconds ago." but after this it works normal.
If I use autoReconnectForPools in url or just don't use it - after idle period (8 hours) I got everytime ".MySQLNonTransientConnectionException: No operations allowed after connection closed".
In both cases things go smoothly while app has load. So, I concluded that connections was closed from side of mysql.
Help, what have I missed? I'd like to solve this problem without changing wait_timeout in Mysql. Goal - stable app which may survive idle times if it occur :)
解决方案
I thought a bit, and decided to leave this question to be, though problem was not in Tomcat DBCP at all. My decision is motivated by the fact that I found quite a number of similar questions, and many of them unanswered, and never found a clue for what might have been going on. So, I leave a message here just as a warning for anyone suddenly walking the same path:
The problem was that I had a resource using database which was initialized just once, like:
class MyClass {
private MyResource res = null;
private MyResource getMyResource() {
if (res == null) res = new MyResource(getConnection());
return res;
}
private Connection getConnection() {
....
con = dataSource.getConnection();
....
return con;
}
}
When my app was in Servlet it led to the situation where instance of MyResource were the only one, and had connection open. So, when MySQL server kill the expired connection my app would get exception about timeout on first query, but owing to autoReconnect for subsequent queries connection will be alive again. Pool just didn't touched connection because it had never been released.
Finally I realized it, and fixed by changing getMyResource to:
private MyResource getMyResource() {
return new MyResource(getConnection());
}
In my case it was reasonable. After this change all things started to work as expected.