首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将IReduceInit从next.jdbc调整为使用cheshire将JSON流到使用ring的HTTP响应

如何将IReduceInit从next.jdbc调整为使用cheshire将JSON流到使用ring的HTTP响应
EN

Stack Overflow用户
提问于 2019-09-23 19:22:22
回答 4查看 340关注 0票数 2

博士如何将IReduceInit转换成转换后的值

我有一个数据库查询,它生成一个相当大的数据集,用于在客户机上进行实时旋转(百万行或两行,25个属性--对于现代笔记本电脑来说没有问题)。

我的(简化)堆栈是调用clojure.jdbc来获得(我认为是懒惰的)结果行序列。我可以通过环形json中间件将其作为主体来序列化。在堆上构建响应字符串时,存在一个问题,但从0.5.0开始,可以选择将响应流出来。

我通过对几个失败案例的分析发现,实际上,clojure.jdbc在返回之前,正在实现内存中的整个结果集。没问题!与其在这个库中使用reducible-query,我决定迁移到新的next.jdbc。

next.jdbc中的关键操作是plan,它返回一个IReduceInit,我可以使用它来运行查询并获得结果集.

代码语言:javascript
复制
(into [] (map :cc_id) (jdbc/plan ds ["select cc_id from organisation where cc_id = '675192'"]))
["675192"]

但是,这就实现了整个结果集,在上面的情况下,它将给我预先和内存中的所有ids。对一个人来说不是问题,但我通常有很多。

计划IReduceInit是一个我可以减少的东西,如果我给一个起始值,所以我可以做输出在还原函数.(thx @thx合金)

代码语言:javascript
复制
(reduce #(println (:cc_id %2)) [] (jdbc/plan ds ["select cc_id from organisation where cc_id = '675192'"]))
675192
nil

理想情况下,在向...but应用转换函数之后,我希望将这个IReduceInit转换成一个值的懒序列,这样我就可以将它们与ring-json和cheshire一起使用。我看不出有什么明显的方法。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-08-26 19:45:40

我的懒惰-seq是个坏主意,有很多原因--即使我保证不抱着头,结果流中的异常问题无疑会让ResultSet无所适从--序列化将发生在调用堆栈之外,而调用堆栈可能会被清理。

懒惰的需要是由没有意识到记忆的全部结果的欲望所驱动的,是因为需要一个塞克还是其他的科尔?是为了让中间件将其序列化..。

因此,直接制作IReduceInit JSONable,然后绕过中间件。如果在序列化过程中出现异常,则控件将通过来自IReduceInit的next.jdbc传递,这样就可以进行有意义的清理。

代码语言:javascript
复制
;; reuse this body generator from my patch to ring.middleware.json directly, as the coll? check will fail
(defrecord JsonStreamingResponseBody [body options]
  ring-protocols/StreamableResponseBody
  (write-body-to-stream [_ _ output-stream]
    (json/generate-stream body (io/writer output-stream) options)))
 
;; the year long yak is shaved in 8 lines by providing a custom serialiser for IReduceInits…
(extend-type IReduceInit
  cheshire.generate/JSONable
  (to-json [^IReduceInit results ^JsonGenerator jg]
    (.writeStartArray jg)
    (let [rf (fn [_ ^IPersistentMap m]
               (cheshire.generate/encode-map m jg))]
      (reduce rf nil results))
    (.writeEndArray jg)))

;; at this point I can wrap the result from next.jdbc/plan with ->JsonStreamingResponseBody into the :body of the ring response and it will stream

编写这些特性仍然需要大量的工作,适配器代码总是让我担心我缺少一种简单的、惯用的方法。

票数 1
EN

Stack Overflow用户

发布于 2019-09-23 20:26:25

reduce在IReduceInit中工作得很好。IReduceInit需要一个初始值,这是在调用.reduce时指定的,而不是在使用reduce函数时指定的;这解释了为什么您看到其中一个在工作,而另一个却没有工作。

然而,这不会得到一个懒惰的序列。reduce合同的一部分是它急切地消耗了整个输入(我们将忽略reduced,它不会改变任何有意义的东西)。您的问题是更普遍的动态范围问题的一个具体案例: JDBC生成的序列仅在某些上下文中“有效”,您需要在这个上下文中完成所有处理,所以不能懒惰。相反,您通常将程序内翻:不要使用返回值作为序列,而是向查询引擎传递一个函数,并说:“请用结果调用此函数”。然后,引擎在调用该函数时确保数据是有效的,并且一旦函数返回,它就清理数据。我不知道jdbc.next,但是对于旧的jdbc,您将使用类似于db-query-with-resultset的东西来实现这个功能。您将传递一些函数,该函数可以将字节添加到挂起的HTTP响应中,并且它将多次调用该函数。

这有点模糊,因为我不知道您使用的是什么HTTP处理程序,也不知道它用于非懒惰地处理流响应的工具是什么,但是如果您想要处理动态范围的资源,则必须遵循这样的一般想法:懒惰不是一种选择。

票数 2
EN

Stack Overflow用户

发布于 2019-09-24 06:58:20

令人沮丧。

为什么不能用JDBC来完成这个任务呢?没有任何隐蔽层吗?

代码语言:javascript
复制
(let [resultset (.executeQuery connection "select ...")]
  (loop 
   (when (.next resultset)
     (let [row [(.getString resultset 1)
                (.getString resultset 2)
                ...]])
     (json/send row)
     (recur)))
  (json/end))

当然,使用ResultSetMetaData,您可以将行的生成自动化为一个可以处理返回的任何内容的函数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58068904

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档