服务器环境

Windows Server 2008 R2

MySQL 5.7.17

类库版本

spring 4.0.2

mybatis 3.2.6

mysql-connector-java 5.1.30


异常信息:

### Error updating database.  Cause: java.sql.SQLException: Could not retrieve transation read-only status server

### The error may involve com.raynetwork.signserver.dao.TaskDao.insert-Inline

### The error occurred while setting parameters

### SQL: insert into task (GUID, MemberGUID, TaskID,        Date, Status, FileCount,        UseSelfCert, Deleted)     values (?, ?, ?,        ?, ?, ?,        ?, ?)

### Cause: java.sql.SQLException: Could not retrieve transation read-only status server

; SQL []; Could not retrieve transation read-only status server; nested exception is java.sql.SQLException: Could not retrieve transation read-only status server

[WARN] [2019-07-17 09:29:28][org.springframework.web.servlet.PageNotFound]No mapping found for HTTP request with URI [/favicon.ico] in DispatcherServlet with name 'SpringMVC'


寻找问题的过程:

1.定位问题过程

1.由于该服务器上的数据库是和另外一个项目公用的,就以为是另外一个项目影响了数据库服务,经过排查发现并不是。

2.经过网上搜素,有以下几个结果,(1)mysql与jdbc驱动包不对应;(2)连接字符串后面加serverTimezone=UTC;(3)调整mysql的事物隔离级别。但是经过测试,均未解决。

3.后来同事提到了在报错信息中提示了一个时间很长的超时信息,:

4.又经过查询,最后找到了下面这篇文章

https://www.cnblogs.com/kuexun/p/9818468.html


问题描述:

大部分客户端都使用连接池以提高性能,如果用户访问量不大,连接池中的连接可能闲置时间超过数据库允许时间,数据库单方面断掉连接,而客户端却不知情。当下一个用户访问时,使用连接池中的连接,则会抛出上述异常。

我理解就是应用程序维护了一个数据库连接池,每次数据库操作的时候从使用连接池中的链接去访问数据库,但由于我们这个程序是一个不怎么常用的服务,可能三两天才会使用一次,这时候就有问题了,连接池中的链接虽然还存在于应用程序中,但是对数据库而言它已经超时,数据库便将其关闭,但是应用程序不知道这条链接已经被数据库关闭,当下一个用户使用这个服务的时候,应用程序便使用这条链接去请求数据库,这时候就会发生这个异常。

如何解决:

解决这个问题的根本方法就是定时的使用连接池中的链接去请求数据库,建立心跳机制,保持连接

参照上面文章提供的解决方案已经成功解决这个问题,既在mybatis的配置文件中指定以下三个配置项

<property name="poolPingEnabled" value="true"/>

<property name="poolPingQuery" value="select 1"/>

<property name="poolPingConnectionsNotUsedFor" value="3600000"/>

poolPingEnabled - 默认值是false,当值为true的时候,将开启ping机制。

poolPingQuery - 对数据库进行ping时所使用的sql。

poolPingConnectionsNotUsedFor - 默认值是0,单位是毫秒。我们不能在每次使用连接池之前,都使用ping机制,这会使每一条sql的执行,都要额外执行一次ping语句。所以使用此属性来避免这种不合理做法。我们只针对闲置时间超过某个时间的连接,进行ping。本例中的值为1小时,当从连接池中拿出的连接闲置超过1小时,才会对它进行ping。