::clojure jdbc中的结果集-fn返回错误“结果集已关闭。” 为什么?

Але*_*бер 5 database sql-server postgresql jdbc clojure

通常,我需要从数据库服务器加载巨大的数据量。有时它有上百万行甚至更多。因此,我尝试延迟下载数据。那就是我想要做的:我想获得一个惰性序列并从服务器中提取部分数据,即,如果行数超过500,我主要希望首先获得该惰性序列的前500个元素,然后通过另一个请求得到我要接收下500个元素,依此类推,直到我从服务器接收到所有数据。

但是我有一个问题。Clojure jdbc实现了整个惰性序列,但是我想部分地从中获取数据。我研究了这个问题,并找到了关于类似问题的良好答案: clojure.java.jdbc惰性查询

我以这个例子为例:


(defn get_data
   [arg1 arg2]
   (let [full-db-spec (get ...)
       sql_query (get ...)
       row-n (atom 0)
       prepared-statement (-> full-db-spec
                               (jdbc/get-connection)
                               (jdbc/prepare-statement sql_query {:fetch-size 3}))]
     (jdbc/with-db-transaction [tx full-db-spec]
       (jdbc/query full-db-spec [prepared-statement arg1 arg2]
           {:fetch-size 3
            :row-fn (fn [r] (do (prn "r" @row-n) (swap! row-n inc) r))
            :result-set-fn identity}))))
Run Code Online (Sandbox Code Playgroud)

在这里,我想获得一个惰性序列,以进一步从该惰性序列中部分提取数据。但是何时:result-set-fn包含identity(take 500 ...)代码返回错误:The result set is closed.为什么?但是,当我将:result-set-fn更改为first或doall或last时,它工作正常,但它实现了完整的延迟序列!

我用:

  • ms sql [com.microsoft.sqlserver/mssql-jdbc "6.3.3.jre8-preview"](但是我在postgresql上进行了测试[org.postgresql/postgresql "9.4.1212.jre7"]。结果相同)
  • [org.clojure / java.jdbc“ 0.7.3”]

Sva*_*nte 4

该惰性序列正在从连接中读取值,但连接在范围之外关闭with-db-transaction。您需要在该范围内实现/进行进一步处理。

  • 我 100% 同意这个答案,并补充说,“with-db-transaction”使用动态范围的*原因*是您不能/不应该在数据库连接方面偷懒。保持一个开放的状态需要消耗真实的、耗尽的资源。在这种情况下,你不会享受到懒惰的奢侈。决定要如何处理结果,并在“with-”范围内完成所有操作。 (4认同)
  • 我正在为 clojure 中的此类 bug 推广术语“lazybug”。 (2认同)