我有一个应用程序,它使用 HikariCP 对使用 JTDS 的 SQL Server DB 进行连接池。如果我让应用程序运行过夜,早上第一个查询将挂起,并显示下面的堆栈跟踪。如果我再次请求,那么新的查询将正常工作。我是否缺少一个超时来阻止第一个查询挂起?它似乎挂起大约 10->20 分钟,然后开始工作。因此,10->20 分钟后,sockRead 和挂起的线程就会消失。我认为挂起的查询随后完成,但我可能是错的。我的 Hikari 配置也如下。
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(SocketInputStream.java:-1)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.DataInputStream.readFully(DataInputStream.java:195)
at java.io.DataInputStream.readFully(DataInputStream.java:169)
at net.sourceforge.jtds.jdbc.SharedSocket.readPacket(SharedSocket.java:850)
at net.sourceforge.jtds.jdbc.SharedSocket.getNetPacket(SharedSocket.java:731)
- locked <0xeeb> (a java.util.concurrent.ConcurrentHashMap)
at net.sourceforge.jtds.jdbc.ResponseStream.getPacket(ResponseStream.java:477)
at net.sourceforge.jtds.jdbc.ResponseStream.read(ResponseStream.java:114)
at net.sourceforge.jtds.jdbc.ResponseStream.peek(ResponseStream.java:99)
at net.sourceforge.jtds.jdbc.TdsCore.wait(TdsCore.java:4127)
at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java:1086)
- locked <0xeec> (a net.sourceforge.jtds.jdbc.TdsCore)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:563)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeImpl(JtdsStatement.java:809)
at net.sourceforge.jtds.jdbc.JtdsStatement.execute(JtdsStatement.java:1282)
at com.zaxxer.hikari.pool.PoolElf.isConnectionAlive(PoolElf.java:224)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:188)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:163)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:85)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:204)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
光配置:
hconf.setJdbcUrl(url) // url looks like: jdbc:jtds:sqlserver://host/DB
hconf.setConnectionTestQuery("select 1")
hconf.setDriverClassName("net.sourceforge.jtds.jdbcx.JtdsDataSource")
// set username and password
hconf.setConnectionTimeout(5 * 1000)
hconf.setValidationTimeout(1000)
hconf.setIdleTimeout(10 * 60 * 1000)
hconf.setMaxLifetime(30 * 60 * 1000)
hconf.setLeakDetectionThreshold(60 * 1000)
hconf.setInitializationFailFast(false)
val numThreads = 10
hconf.setMaximumPoolSize(numThreads * 5)
hconf.setMinimumIdle(numThreads)
hconf.setPoolName(name)
hconf.setRegisterMbeans(false)
光CP:2.4.1
JTDS:1.3.1
更新:
我现在知道问题出在哪里了。在 HikariCP isConnectionAlive
中,它会在调用 setConnectionTestQuery
中设置的查询之前尝试将网络超时设置为上面 setValidationTimeout
中指定的值。但是,JTDS 不支持 java.sql.Connection.setNetworkTimeout,因此读取超时是操作系统默认值。大约需要 10 分钟。
理论上,您应该能够设置驱动程序属性套接字超时作为解决方法(尽管它对我不起作用)。但这并不是一个很好的解决方法,因为您确实希望测试查询与实际查询的查询超时不同。
所以这不是 HikariCP 问题,而是 JTDS 问题。
最佳答案
我建议通过 log4j 或您正在使用的任何日志框架为 HikariCP 包启用调试级别日志记录。 HikariCP 应记录连接停用和创建,您可以使用它来验证连接是否在其配置的 maxLifetime
处正确循环。
但是,查看您发布的堆栈跟踪,在 HikariCP isConnectionAlive()
检查期间,该线程似乎卡在 JTDS 驱动程序中。 HikariCP 在这里无能为力。不过这很奇怪。
您说“早上第一个查询将挂起”。电脑要休眠了吗? SQL Server 会休眠吗?这样做会阻止 HikariCP 在夜间正常循环连接。同样,调试日志记录在这里会有所帮助——即使应用程序处于空闲状态,夜间也应该有相当定期的停用和创建事件。
关于jtds - HikariCP 卡在 getConnection 上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34739778/