我正在尝试为jdbc/query
和jdbc/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支持连接字符串中的connectionTimeout
和socketTimeout
- 两者都以毫秒为单位。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)")))