我有一个使用HikariCP的应用程序,用于使用JTDS对SQL Server数据库进行连接池。如果我让应用程序一夜之间运行,早上第一个查询将挂起,下面是堆栈跟踪。如果我再次请求,则新查询将正常工作。我错过了超时,会阻止第一个查询挂起吗?它似乎挂了大约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)
Hikari配置:
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)
HikariCP:2.4.1
JTDS:1.3.1
更新
我现在知道问题所在。在HikariCP isConnectionAlive
中,它会在调用setValidationTimeout
中的查询集之前尝试将网络超时设置为setConnectionTestQuery
中上面指定的内容。但JTDS不支持java.sql.Connection.setNetworkTimeout
,因此读取超时是操作系统默认值。大约10分钟。
理论上,您应该能够将驱动程序属性套接字超时设置为解决方法(尽管它对我不起作用)。但这不是一个很好的工作,因为你真的希望查询超时对于测试查询与真实查询不同。
所以这不是一个HikariCP问题,它是一个JTDS问题。
答案 0 :(得分:2)
我建议通过log4j或您正在使用的任何日志记录框架为HikariCP软件包启用调试级别日志记录。 HikariCP应记录连接退出和创建,您可以使用它来验证连接是否在其配置的maxLifetime
处正常循环。
但是,查看您发布的堆栈跟踪,在HikariCP isConnectionAlive()
检查期间,该线程似乎挂在JTDS驱动程序中。没有太多的HikariCP可以在这里帮忙。不过很奇怪。
你说“早上第一个查询会挂起”。电脑会睡觉吗? SQL Server会睡觉吗?这样做可以防止HikariCP在夜间正常循环连接。再次,调试日志记录在这里会有所帮助 - 即使应用程序处于空闲状态,也应该在一夜之间进行相当规律的报废和创建活动。
答案 1 :(得分:0)
如果你更新到2.4.3,它在getConnection()和其他一些在某些/类似情况下修复了问题的细微变化。 请报告是否解决了行为或堆栈跟踪或产生任何差异