Clojure 中的 Java/JDBC 超时



我正在尝试为jdbc/queryjdbc/execute!添加超时。在网络上的某个地方,我发现这两个功能都:timeout作为一种选择。Documention还表示,这些选项被传递给prepare-statment,后者将:timeout作为一种选择。

我的函数调用如下所示,

(jdbc/query db-read-spec query {:timeout 2})
(jdbc/execute! db-write-spec query {:timeout 2})

是这样做到的吗?如果是,我该如何测试?

如果有不同的方法可以测试,那也有效。

:timeout选项会导致在clojure.java.jdbc引擎盖下使用的PreparedStatement上调用.setQueryTimeout。它以秒为单位,而不是毫秒,因此查询必须非常慢才能使 2,000(半小时多一点)的超时生效。

JDBC 在其多个类中支持几种不同的超时。例如,javax.sql.DataSource支持.setLoginTimeout(也以秒为单位),java.sql.DriverManager也是如此。

还可以将特定于数据库的选项添加到连接字符串(可以在"db-spec"中将其添加为其他键/值对)以控制较低级别的超时。例如,MySQL支持连接字符串中的connectionTimeoutsocketTimeout- 两者都以毫秒为单位。clojure.java.jdbc允许在"db-spec"哈希映射中分别以:connectTimeout键和:socketTimeout键的形式提供这些键。

请注意,此时clojure.java.jdbc被认为是"稳定"的,此时所有当前和未来的开发工作都集中在next.jdbc上。next.jdbc使得使用该loginTimeout变得更加容易,因为它直接在JDBC对象上运行,因此整个(Java)API也可用。它还内置了对连接池的支持,总体而言,它比clojure.java.jdbc更简单、更快

您可以在 mysql-select-query 上利用查询提示(以毫秒为单位的时间)

SELECT /*+ MAX_EXECUTION_TIME(1000) */ * FROM t1 INNER JOIN t2 WHERE....

然后,您可以包装查询:

(defn timed-query [db query t]
(j/query db [(str (subs query 0 6)
(format " /*+ MAX_EXECUTION_TIME(%s) */ " t)
(subs query 7))]))

并测试:

(deftest test-query-timeout
(is (thrown? Exception (timed-query db "select * from Employees where id>5" 1))))

您应该使用非常复杂的查询来使其与 1ms 一起使用;

我想出了一个解决方法来测试这一点。由于我使用postgres,所以我可以利用select pg_sleep(time-in-seconds)

我的测试看起来像

(is (thrown-with-msg? PSQLException #"ERROR: canceling statement due to user request"
(fetch-or-save "select pg_sleep(3)")))

最新更新