线程无法获取到数据库连接知多少
如果线程在操作过程中被设置为中断状态,则该线程在操作数据库获取数据库连接的时候会出现无法获取到数据库连接的异常,所以最好不要在中断的线程下做资源的操作。线程中断并不等于终止线程
JDBC无法获取到连接的异常基本是比较常见的,一般常见的原因有:1. 数据库的账号或密码错误 2.当前服务器无法连接到数据库服务器。但是这个异常:org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: interrupt
或者这个异常:
nested Exceepiton is java.sql.SQLException: interrupt###Cause: org.springframework.jdbc.CannotGetjdbcConnectionException: Failed to obtaion JDBC Connection: nested exception is java.sql.SQLException: interrupt
并不是简单的无法连接到数据库的原因,下面将简单进行分析
原因
-
异常的区别:
第一个异常和第二个异常都是操作数据库异常,第一个异常信息中提示:无法打开事务的连接,第二个异常信息中提示:无法获取到数据库连接,实际上都是相同的原因
- 第一个异常是因为在发生异常的方法上开启了事务,所以开启事务的时候无法获取到数据库连接异常
- 第二个异常是因为在操作数据库的时候没有开启事务,所以直接获取数据库连接异常
-
原因分析
-
根据提示中信息
interrupt
来看,刚开始认为是获取数据库连接的时候被中断了,所以无法获取到数据库连接,分析可能是网络原因或者是数据库连接池耗尽,所以导致异常。但是根据查看相关数据,并不是数据库连接使用完导致的,而且该异常也较为频繁发生,看起来和网络原因关系也并不是特别大。 -
连接Mysql数据库的连接池为Druid,根据提示的异常信息,进一步到Druid报错的位置追踪信息,异常的报错位置:
DruidDataSource#getConnectionInternal
-
相信看到这里,基本上都已经明白是怎么回事了,可以看到并不是网络原因导致的获取数据库连接中断了,而是上面的
this.lock.lockInterruptibly();
这行代码出错,导致抛出异常。 -
进一步分析,
this.lock.lockInterruptibly();
这行代码为什么会报错呢?看起来这个就是ReentrantLock#lockInterruptibly
加锁的方法,进一步看看为什么会抛出异常:lockInterruptibly
加锁方法在获取锁的时候会判断当前线程是否被中断,如果线程处于中断状态,那么该线程就会抛出异常,导致无法获取到数据库连接。
-
结论
如果当前线程在获取数据库连接池之前被中断,那么该线程就会被设置一个中断状态,在使用Druid连接池获取数据库连接时,会先进行加锁,使用ReentrantLock#lockInterruptibly
加锁,该方法在加锁之前会先判断线程是否被中断,如果当前线程被中断,那么抛出异常,该异常被try…catch,然后被Druid抛出SQLException
的异常,导致无法获取到数据库连接。
所以尽量不要在中单的线程下做资源的操作,中断的线程也不意味该线程立即终止,而是给该线程设置为中断的标志,该线程还可以正常执行。
线程被中断的场景例如:sleep中的线程被中断,正在执行的线程被Hystrix中断(达到Hystrix的超时时间发生熔断)