最近在用Servlet开发小项目的时候发现,项目在本地调试的时候一切正常,但是正式部署到服务器后,会出现各种问题。访问会出现500抛出异常,必须手动重启Tomcat。百度后知道了问题出在MySQL的一个机制,也就是“八小时问题”。
MySQL服务器默认的“wait_timeout”是8小时,如果一个连接空闲时间超过8小时,那么MySQL将会自动将这个Connection断开。但是MyBatis并不知道这个Connection已经失效,处理业务时仍然会提交这个已经失效的Connection,就导致了上述异常。
解决的方法有两种,一是从MySQL入手,修改其“wait_timeout”属性来达到延长连接有效时间的目的。但是“wait_timeout”最大支持的值也只有2147483,只能维持大概24天左右的连接,治标不治本。并且,长时间保留闲置连接会降低数据库的性能,消耗内存。
另一种方法是从MyBatis入手,让它在使用闲置连接之前先ping一下,确保这个连接还在正常工作。在MyBatis的连接池中这样定义:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="poolPingEnabled" value="true"/>
<property name="poolPingQuery" value="这里填写用于ping的sql语句;"/>
<property name="poolPingConnectionsNotUsedFor" value="3600000"/>
</dataSource>
</environment>
</environments>
设置连接池是,需要声明三个属性:
- poolPingEnabled:默认值为false,值为true时开启ping机制。
- poolPingQuery:对数据库ping操作时所使用的sql语句。
- poolPingConnectionsNotUsedFor:默认值为0,单位毫秒。表示闲置超过多少时间后才会进行ping。因为不可能每次使用连接池之前都ping一下,这样会额外执行一句sql影响效率。本例中设置为一小时,只有连接池中的连接闲置超过一小时才会执行操作。
6月20日更新:尝试更换了阿里云的Druid连接池,经过几日的测试,发现八小时问题已经解决,并且查询速度有了较大提升。连接池的选择会直接影响到项目的稳定性与运行性能。




Comments | NOTHING