【发布时间】:2013-11-11 11:03:49
【问题描述】:
我有一个小程序,它应该一个一个地读取 SQL 查询/命令并针对数据库执行它们。
如果一个查询成功执行,则执行下一个查询。 如果执行一个查询出错,程序应该一起停止执行。
我有代码,只是查询在出现异常时仍会继续执行。
(defn main
[]
(loop [queries (get-all-queries)
querycount 1]
(let [q (first queries)]
(println (format "currently processing query %s", querycount))
(cond (nil? q) (println "All Queries ran successfully.")
:else (do
(cond (= (:status (process-query q querycount)) "OK")
(recur (rest queries) (+querycount 1)))
:else (println "An error occured while running queries")))))))
(defn process-query
[query query-count]
(let [{query-body :query-body, is-query-running? :is-query-running?} query
my-agent (agent
{:error false, :query-count query-count}
:error-handler handler-fn)]
(send my-agent (fn[_]
(execute-query! db query-body)))))
(loop [is-query-running? (is-query-running?)
error? (:error @my-agent)]
(cond error? (do (println "Error")
{:status "ERROR" :error-msg (:error-msg @my-agent)})
(and (not is-query-running?) (not error?)) (do (println "Success")
{:status "OK"})
(:else (do
(Thread/sleep 2000)
(recur (is-query-running?) (:error @my-agent)))))))
(defn handler-fn
[agent exception]
(println (format "an exception occured : %s" exception))
(if (instance? java.sql.BatchUpdateException exception)
(println (.getNextException exception)))
(send agent (? [_] {:error true, :error-message exception}))
(throw exception))
我使用代理的原因是我有一些查询需要 4 小时才能运行。 当这种情况发生时,数据库不会通知程序查询已经完成。相反,程序卡住了。所以,相反,我不断轮询以检查查询是否已经完成。
- 这是完成我想做的事情的最佳方式吗?
- 我应该使用任何其他并发原语吗?
- 我什至需要并发原语吗?
- 这个问题我想了很久。
【问题讨论】:
-
is-query-running?是如何工作的。从您的代码中不清楚,因为它作为每个查询映射中的值传入,并且可能对问题至关重要,因为如果is-query-running?在代理的:error键之前变为 false,process-query将返回"OK"成为真的。 -
查询正在运行吗?运行查询并检索所有主动执行的查询,然后检查当前查询是否在运行的查询中。如果是,则返回 true。
-
如果它返回
true而不是它本身,您应该在recur调用process-query中收到一条错误消息。 Clojure 是一个 Lisp-1,因此返回值true会影响is-query-running?在loop内的函数定义。 -
老兄,请将您的源代码格式化为最多 80 列。
-
@Igrapenthin,对不起伙计。代码格式化。
标签: sql concurrency clojure functional-programming