java.sql.SQLException: connection holder is null

原创
2016/07/29 11:57
阅读数 953

 

调试的时候经常会出现这个问题,原因是事务时间已经达到系统设置的最长值,系统以为超时,切断这个连接,从而调用事务时发生了错误。

这个不仅仅是调试时会发生,再系统中也有发生,比如一个很耗时的流程,因为过程非常耗时,这个耗时操作恰好是在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信号弱,网络不通等,那么客户端抛出异常被捕获,客户端还是顺利的执行了代码,却没有通知服务端,我们这里发生了异常。那么这个时候服务端一直等待客户端的响应,没有超时设置的话,一直占用这个连接,如果有超时的话,达到这个时间,连接就断开了。

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部