2011-02-03 3 views
2

私はUSDAの栄養データベースファイルをASCIIからsqliteデータベースに変換するプログラムに取り組んでいます。これらのファイルに関する情報はhttp://www.ars.usda.gov/Services/docs.htm?docid=8964にあり、本当に素晴らしいものになります。私のSQL接続はfor構造で何が起こっていますか?

ただし、以下のコードでは、変換を行う関数の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 [email protected]> 
((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接続を再度印刷しようとすると例外がスローされます。

何が原因で接続が消滅する可能性がありますか?何か他のことはまったく起こっていますか?

UPDATE:ここでは、SQL /機能は、すべてのすべてのclojure.contrib.sql

答えて

3

forは遅延です。あなたの接続ハンドルがwith-connectionで開かれ、閉じています。forの中でconvert-food-descriptionが評価されています。

接続ハンドルがまだ生きている間は、評価を強制する必要があります。たとえば、fordoseqに変更してみてください。

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 
+0

今私はちょっとばかげていると感じます。以前は怠惰に襲われました。 –

0

まずから来る、あなたの(println (sql/connection))はあなたの現在の接続を印刷していません。代わりに新しいものを作成し、それを印刷します。

第二に、あなたはこれが、これは単に接続の説明オープン接続されていません(def db {:classname "com.sqlite.JDBC" :subprotocol "sqlite" :subname "nutrition.sqlite"})

としてデシベルを定義しています。

第3に、dbをパラメータとしてconvert-food-descriptionメソッドに渡し、実際のクエリに使用する必要があります。

+0

データベースはwith-connectionによって開かれ、* db *にバインドされます。 insert-values、insert-rows、create-tableなどの関数はdo-preparedを呼び出し、* db *に格納されている接続を参照します。したがって、dbをパラメータとして渡すことは役に立ちません。 –

関連する問題