在for构造中我的SQL连接发生了什么?

时间:2011-02-03 14:43:31

标签: sql clojure

我正在开发一个程序,将USDA营养数据库文件从ASCII转换为sqlite数据库。有关这些文件的信息可以在http://www.ars.usda.gov/Services/docs.htm?docid=8964找到,相当于非常棒的东西。

但是,在下面的代码中,只要我在执行转换的函数中输入for构造,我的sql连接就“消失”。

(defn sanitize-field [field]
  (cond
    (= field "~~") ""
    (= field "") 0
    (and (.startsWith field "~") (.endsWith field "~"))
      (.substring field 1 (- (.length field) 1))
    :default (try
               (Double. field)
               (catch NumberFormatException n 0.0))))


(defn field-separator [line]
  (.split line "\\^"))

(defn parse-file [file]
  (map (fn [l] (map sanitize-field (field-separator l)))
       (.split (slurp (.getCanonicalPath file)) "\r\n")))

(defn convert-food-description [source-dir]
  (println (sql/connection))
  (for [entry (parse-file (File. source-dir "FOOD_DES.txt"))]
    (do
      (println entry)
      (println (sql/connection))
      (sql/insert-rows "food_des" entry))))

(Class/forName "org.sqlite.JDBC")
(def db {:classname "com.sqlite.JDBC" :subprotocol "sqlite" :subname "nutrition.sqlite"})

(defn convert []
  (sql/with-connection db
    (convert-food-description (File. "/home/savanni/Downloads/nutrient_database"))))

当我运行转换操作时,我得到的是:

user=> (convert)
(convert)
#<Conn org.sqlite.Conn@180e426>
((01001 0100 Butter, salted BUTTER,WITH SALT   Y  0.0  6.38 4.27 8.79 3.87)
java.lang.Exception: no current database connection

所以,我唯一的println命令是转换食物描述。在函数开始执行正常后,它看起来像第一个,打印出我用with-connection语句创建的连接。但是,然后for循环开始,我打印出我要插入数据库的第一行数据,然后在尝试再次打印SQL连接时抛出异常。

什么可能导致连接在那里消失?还有其他事情发生了吗?

更新:这里的sql / functions都来自clojure.contrib.sql

2 个答案:

答案 0 :(得分:3)

for很懒。在with-connection for进行评估之前,convert-food-description正在打开和关闭您的连接句柄。

您必须在连接句柄仍处于活动状态时强制进行评估。例如,尝试将for更改为doseq

user> (require '(clojure.contrib [sql :as sql]))
nil
user> (import 'org.sqlite.JDBC)
org.sqlite.JDBC
user> (def db {:classname "com.sqlite.JDBC" 
               :subprotocol "sqlite" 
               :subname "foo.sqlite"})
#'user/db
user> (sql/with-connection db (sql/create-table "foo" ["val" "int"]))
(0)

;; Bad
user> (defn foo []
        (sql/with-connection db
          (for [x (range 10)]
            (sql/insert-records "foo" {:val x}))))
#'user/foo
user> (foo)
; Evaluation aborted.
;;java.lang.Exception: no current database connection

;; Good
user> (defn foo []
        (sql/with-connection db
          (doseq [x (range 10)]
            (sql/insert-rows "foo" [x]))))
#'user/foo
user> (foo)
nil

答案 1 :(得分:0)

首先,您的(println (sql/connection))未打印当前连接。而是创建新的并打印它。

其次,您已将db定义为(def db {:classname "com.sqlite.JDBC" :subprotocol "sqlite" :subname "nutrition.sqlite"})

这不会打开连接,这只是一个连接描述。

第三,您应该将db作为参数传递给convert-food-description方法,并将其用于实际查询。