调试的时候经常会出现这个问题,原因是事务时间已经达到系统设置的最长值,系统以为超时,切断这个连接,从而调用事务时发生了错误。
这个不仅仅是调试时会发生,再系统中也有发生,比如一个很耗时的流程,因为过程非常耗时,这个耗时操作恰好是在service的事务中发生,事务打开连接必然打开,所以他就会暂用连接的大量时间,导致系统耗时过长(达到连接时长的最大值)而连接断开。
或许你会想到调整这个耗时时长:
spring-mybatis.xml
<!-- 清除无用连接的等待时间 -->
<property name="removeAbandonedTimeout" value="600"/>
另外,对于一些数据库连接耗时很长的操作,我们可以通过 Mybatis 单独设置这个时间,select update insert delete
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为 unset(依赖驱动)。
缺陷,由于大部分系统使用声明式事务(Spring的AOP),而非注解式事务(@Transaction),导致所有的非数据库的业务逻辑都用在了事务上,因为事务是加在 Service上,Service就是所有的业务代码集合,所以,很多非数据库操作的逻辑都加了事务,其实完全没有必要。如果我们使用注解式事务,那么一些逻辑操作是可控的。
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="set*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
连接时间太长导致资源浪费,而且超时是一个很友好的设置,如果没有超时设置,无限制等待,虽然可以解决耗时问题,但是如果遇到系统错误,那就会一直等待,暂用资源。
比如这段代码
// 客户端代码
try{
process()
notifyServer()
}catch(Exception e ){
// do nothing
}
假设这样的处境,服务端想要知道客户端的坐标,发送一个长连接给客户端,客户端就会执行如上的代码,先去 process 获取当前坐标,然后通知服务器。如果,客户端在获取坐标的时候出现了Exception,比如 GPS信号弱,网络不通等,那么客户端抛出异常被捕获,客户端还是顺利的执行了代码,却没有通知服务端,我们这里发生了异常。那么这个时候服务端一直等待客户端的响应,没有超时设置的话,一直占用这个连接,如果有超时的话,达到这个时间,连接就断开了。