我有一个简单的Clojure程序,它查询Oracle数据库并以逗号分隔格式打印出结果 . 这个程序通过Clojure.main正常运行它 . 我想编译这个程序并按照这里的说明操作:
http://java.ociweb.com/mark/clojure/article.html#Compiling
我使用这种方法编译并运行另一个简单的程序就好了 . 所以我不认为这与这种编译方法有任何关系 . 这个程序编译得很好但是当我尝试运行编译的类时它会返回这个错误:
线程“main”中的异常java.lang.RuntimeException:java.lang.RuntimeException:java.sql.SQLException:clojure.lang.LazySeq.seq上clojure.lang.LazySeq.sval(LazySeq.java:47)中的已用尽结果集(LazySeq.java:56)位于clojure.core $ seq__4245.invoke(core.clj:105)的clojure.lang.RT.seq(RT.java:440)at bill.myquery $ dump_db_csv__24.invoke(myquery.clj: 27)在bill.myquery $ main_49.invoke(myquery.clj:41)的clojure.lang.AFn.applyToHelper(AFn.java:171)的clojure.lang.AFn.applyTo(AFn.java:164)at bill . myquery.main(Unknown Source)由以下引起:java.lang.RuntimeException:java.sql.SQLException:clojure.lang.LazySeq.seq(LazySeq . )上的clojure.lang.LazySeq.sval(LazySeq.java:47)中的Exususted Resultset . java:56)at clojure.lang.Cons.next(Cons.java:37)at clojure.lang.RT.boundedLength(RT.java:1128)at clojure.lang.RestFn.applyTo(RestFn.java:135)at clojure.core $ apply__4370.invoke(core.clj:438)at clojure.core $ resultset_seq_6276 $ thisfn_6290 $ fn__6291.invoke(core.clj:3842)at clojure.lang.LazySeq.sval(LazyS) eq.java:42)... 8更多引起:java.sql.SQLException:oracle.jdbc.driver.DatabaseError.throwSqlException上的oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)中的Exususted Resultset( DatabaseError.java:146)oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)at oracle.jdbc.driver.OracleResultSetImpl.getObject(OracleResultSetImpl.java:900)at clojure.core $ resultset_seq__6276 $ row_values_6284 $ fn_6286 .invoke(core.clj:3839)at clojure.core $ map_5053 $ fn_5055.invoke(core.clj:1760)at clojure.lang.LazySeq.sval(LazySeq.java:42)
这里是:
(ns bill.myquery (:gen-class))
;; Import java.sql classes
(import '(java.sql DriverManager Connection PreparedStatement ResultSet))
;; load jdbc/odbc driver
(. Class forName "oracle.jdbc.driver.OracleDriver")
(def dbname "myOracleServer:1522:myOracleDatabase")
(def service_account "account")
(def service_password "password")
(def conn (. DriverManager (getConnection (str "jdbc:oracle:thin:@" dbname) service_account service_password)))
(def sql "
SELECT name, address, phone
FROM addresss_book
ORDER BY name")
;; Function to dump data with comma delimited fields
(defn dump-db-csv [db]
(doseq [rec db] ;; for all rows
(doseq [[key value] rec] ;; for all fields
(if (= key :phone) ;; if last field
(print (.trim (str value))) ;; don't print comma
(print (format "%s%s" (.trim (str value)) ","))))
(println)))
;; Execute query and get recordset
(def rs (.. conn (prepareStatement sql) (executeQuery)))
;; convert recordset to sequence
(def rset (resultset-seq rs))
;; Main call the function to print rows
(defn -main (dump-db-csv rset))
;; close the recordset
(. rs (close))
2 回答
不要使用
def
- 顶层的所有内容都是在类加载时(或甚至在编译时)执行的,因此在运行-main
之前关闭结果集(rs
) . 始终在单个功能中打开和关闭连接 - 它可以防止很多错误 .另请考虑使用clojure.contrib.sql . 很好的例子可以在wikibooks找到 .
对于这两种方法,不要忘记使用
doall
进行任何可能的延迟序列 .我接受了Andrei的建议并使用了clojure.contrib.sql . 它确实使这更简单,更不容易出错 . 我仍然不想放弃db和sql全局变量的def .
谢谢安德烈