最近做一个小应用,启动后刚开始访问时报错,但是多点几次就好了,就没在意。应用里面有定时,分别是上午10点,11点和12点各执行一次。奇怪的是10点的定时执行的时候会报下面的错误,11点和12点的就没问题。然后我把10点的定时改成每分钟一次就没事了。连着两三天一直这样就觉得很奇怪。报错异常如下:
The last packet successfully received from the server was 8,268,658 milliseconds ago. The last packet sent successfully to the server was 8,268,659 milliseconds ago.
at sun.reflect.GeneratedConstructorAccessor187.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1121)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3938)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2551)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2809)
at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:5333)
at org.apache.commons.dbcp.DelegatingConnection.setAutoCommit(DelegatingConnection.java:371)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.setAutoCommit(PoolingDataSource.java:328)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:72)
... 66 more
Caused by: java.net.SocketException: Connection timed out
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3919)
... 73 more
话不多说接着百度,说是mysql数据库对于长时间没有使用的连接会回收。由于我的应用基本就是那三个定时在跑,所以想着应该是这个问题,改连接池:
最开始我用的连接池是在xml里面配置的:
为了解决这个问题,我直接在tomcat值配置连接池,修改tomcat/conf/context.xml
在Context节点里加入如下内容:
<Resource name="cnhr"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="XXXX"
maxIdle="30"
maxWait="10000"
maxActive="100"
testOnBorrow="true"
testWhileIdle="true"
validationQuery="select 1 from dual" // 检查连接是否可以
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://XXXXXXX" />
url我改了,这里配置成自己的就可以了。
修改后启动报错,大体是密码里有特殊字符 & ,最后将&改成 & 代替,然后将url里面的&也替换成 & 保存后再启动,观察了两三天果然不报错了。
这里的配置大概就是提前检测连接是否可用,避免应用直接拿到不可用的连接报错