强制 Hikari/Hibernate 关闭陈旧的(泄露的?)连接

Force Hikari/Hibernate to close stale (leaked?) connections

我正在使用 Hibernate 5.3 和 Hikari 2.7 在 Spring Boot 2 中通过 the official JDBC driver 使用 FileMaker 16 数据源。

FileMaker 服务器性能较差,SQL 大表的查询执行时间可达一分钟。有时它会导致连接泄漏,当连接池充满了从未释放的活动连接时。

问题是如何强制池中已挂起两分钟的活动连接关闭,将它们移至空闲状态并可供再次使用。

例如,我使用 org.springframework.data.repository.PagingAndSortingRepository 中的 findAll 方法通过 RestController 访问 FileMaker 数据源:

@RestController
public class PatientController {

    @Autowired
    private PatientRepository repository;

    @GetMapping("/patients")
    public Page<Patient> find(Pageable pageable) {
        return repository.findAll(pageable);
    }
}

在原始文件中多次调用 /patients 会导致连接泄漏,这是 Hikari 报告的内容:

2018-09-20 13:49:00.939 DEBUG 1 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Pool stats (total=10, active=10, idle=0, waiting=2)

它也会抛出这样的异常:

java.lang.Exception: Apparent connection leak detected
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128) ~[HikariCP-2.7.9.jar!/:na]

我需要的是,如果 repository.findAll 花费的时间超过 N 秒,则必须终止连接并且控制器方法必须抛出异常。如何实现?

这是我的 Hikari 配置:

 allowPoolSuspension.............false
 autoCommit......................true
 catalog.........................none
 connectionInitSql...............none
 connectionTestQuery............."SELECT COUNT(*) FROM Clinics"
 connectionTimeout...............30000
 dataSource......................none
 dataSourceClassName.............none
 dataSourceJNDI..................none
 dataSourceProperties............{password=<masked>}
 driverClassName................."com.filemaker.jdbc.Driver"
 healthCheckProperties...........{}
 healthCheckRegistry.............none
 idleTimeout.....................600000
 initializationFailFast..........true
 initializationFailTimeout.......1
 isolateInternalQueries..........false
 jdbc4ConnectionTest.............false
 jdbcUrl.........................jdbc:filemaker://***:2399/ec_data
 leakDetectionThreshold..........90000
 maxLifetime.....................1800000
 maximumPoolSize.................10
 metricRegistry..................none
 metricsTrackerFactory...........none
 minimumIdle.....................10
 password........................<masked>
 poolName........................"HikariPool-1"
 readOnly........................false
 registerMbeans..................false
 scheduledExecutor...............none
 scheduledExecutorService........internal
 schema..........................none
 threadFactory...................internal
 transactionIsolation............default
 username........................"CHC"
 validationTimeout...............5000

HikariCP 只关注连接池管理,以管理它从中形成的连接。

loginTimeout - HikariCP 等待与数据库建立连接的时间(基本上是 JDBC 连接)

spring.datasource.hikari.connectionTimeout=30000

maxLifetime - 连接在关闭前在池中存活多长时间

spring.datasource.hikari.maxLifetime=1800000

idleTimeout - 未使用的连接在池中存在多长时间

spring.datasource.hikari.idleTimeout=30000

如果请求超过定义的超时时间,请使用 javax.persistence.query.timeout 取消请求。

javax.persistence.query.timeout(长-毫秒)

The javax.persistence.query.timeout hint defines how long a query is allowed to run before it gets canceled. Hibernate doesn’t handle this timeout itself but provides it to the JDBC driver via the JDBC Statement.setTimeout method.

filemaker JDBC 驱动程序忽略 javax.persistence.query.timeout 参数,即使在 java.sql.setQueryTimeout setter 的驱动程序实现中设置了超时值。因此,我通过扩展 class com.filemaker.jdbc.Driver 并覆盖 connect 方法解决了这个问题,以便将 sockettimeout 参数添加到连接属性。有了这个参数,如果在超时期间没有数据来自套接字,FM JDBC 驱动程序会中断连接。

我还向 filemaker 提交了一个问题:https://community.filemaker.com/message/798471