首页 > 解决方案 > 如何防止validationQueryTimeout影响H2中的其他SQL语句

问题描述

我正在使用支持 H2 1.4.199 数据库的 Dropwizard 1.3.12。在我的数据库配置中

database:
  ...
  validationQuery: "/* MyService Health Check */ SELECT 1"
  validationQueryTimeout: 3s
  ...

我遇到的问题是 3s 的超时也会传播到 Dropwizard 应用程序中完成的真实数据库查询。一些数据库查询被此超时中断。我宁愿让他们再等一会儿。

据我了解validationQueryTimeout,应该只控制validationQuery. 应用程序内部完成的真实数据库请求不应受此影响。我已经尝试删除validationQueryTimeout,这似乎可以解决问题并删除查询超时。这样做我认为是最后的解决方法,因为我认为在从连接池中获取连接时验证连接是否已启动并正在运行的查询超时是有意义的。

我尝试使用 Postgresql,validationQueryTimeout似乎并没有影响其他数据库查询。

我做了一些调试,认为我找到了原因,但我缺乏一个好的解决方法。

在进行验证时,tomcat-jdbc 在验证语句上设置查询超时。 https://github.com/apache/tomcat/blob/9.0.16/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java#L536-L544

            stmt = connection.createStatement();

            int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
            if (validationQueryTimeout > 0) {
                stmt.setQueryTimeout(validationQueryTimeout);
            }

            stmt.execute(query);
            stmt.close();

这里最大的问题是 H2 将超时保持在连接级别而不是语句级别。https://github.com/h2database/h2database/blob/version-1.4.199/h2/src/main/org/h2/jdbc/JdbcStatement.java#L695-L717

    /**
     * Sets the current query timeout in seconds.
     * Changing the value will affect all statements of this connection.
     * This method does not commit a transaction,
     * and rolling back a transaction does not affect this setting.
     *
     * @param seconds the timeout in seconds - 0 means no timeout, values
     *        smaller 0 will throw an exception
     * @throws SQLException if this object is closed
     */
    @Override
    public void setQueryTimeout(int seconds) throws SQLException {
        try {
            debugCodeCall("setQueryTimeout", seconds);
            checkClosed();
            if (seconds < 0) {
                throw DbException.getInvalidValueException("seconds", seconds);
            }
            conn.setQueryTimeout(seconds);
        } catch (Exception e) {
            throw logAndConvert(e);
        }
    }

有什么我可以做的吗?或者是否需要在 h2 或 tomcat-jdbc 中进行修复?我能想到的是在为验证查询设置它之前在 tomcat-jdbc 中获取当前查询超时值,然后在运行验证查询后将其设置回该值。

标签: javah2dropwizardtomcat-jdbc

解决方案


你是对的,这是 H2 的一个已知限制(见这里这里

我想您可以将超时设置为 0 以避免 H2 的错误行为。然后实现一个JdbcInterceptor在语句执行后检查超时。但是,它不会在违反超时时中止语句,只会在之后报告异常:-(


推荐阅读