如果mysql客户程序发送查询时断开与服务器的连接,它立即并自动尝试重新连接服务器并再次发送查询。然而,即使mysql重新连接成功,你的第1个连接也已经结束,并且以前的会话对象和设定值被丢失:包括临时表、自动提交模式,以及用户和会话变量。该行为很危险,如下面的例子所示,服务器将在你不知道的情况下关闭并重启:
代码语言:javascript复制mysql> SET @a=1;
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO t VALUES(@a);
ERROR 2006: MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 1
Current database: test
Query OK, 1 row affected (1.30 sec)
mysql> SELECT * FROM t;
------
| a |
------
| NULL |
------
1 row in set (0.05 sec)
@a用户变量已经随连接丢失,并且重新连接后它也没有定义。如果有必要在连接断开时终止mysql并提示错误,你可以用--skip-reconnect选项启动mysql客户程序。
实例:
页面报错:
项目上线之后每天都会报错,每次都要tomcat重启才行。
HTTP Status 500 - org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.transaction.TransactionSystemException: Could not roll back Hibernate transaction; nested exception is org.hibernate.TransactionException: JDBC rollback failed
org.springframework.transaction.TransactionSystemException: Could not roll back Hibernate transaction; nested exception is org.hibernate.TransactionException: JDBC rollback failed
org.hibernate.TransactionException: JDBC rollback failed
org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:204)
com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Connection.close() has already been called. Invalid operation in this state.
分析原因:
之所以会出现这个异常,是因为Mysql在5以后针对超长时间DB连接做了一个处理,那就是如果一个DB连接在无任何操作情况下过了8个小时后,Mysql会自动把这个连接关闭。所以使用连接池的时候虽然连接对象还在但是链接数据库的!
解决的方法有3种:
增加wait_timeout的时间。
减少Connection pools中connection的lifetime。
测试Connection pools中connection的有效性。
我选择了wait_timeout修改成10年,它的单位是秒;个人觉得并没有大问题,因为只是告诉数据库不要处理长连接了。