我有一个简单的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.sval(LazySeq.java:47) 在clojure.lang.LazySeq.seq(LazySeq.java:56) 在clojure.lang.RT.seq(RT.java:440) 在clojure.core $ seq__4245.invoke(core.clj:105) 在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) 在bill.myquery.main(未知来源) 引起:java.lang.RuntimeException: java.sql.SQLException:用尽了 结果集 在clojure.lang.LazySeq.sval(LazySeq.java:47) 在clojure.lang.LazySeq.seq(LazySeq.java:56) 在clojure.lang.Cons.next(Cons.java:37) 在clojure.lang.RT.boundedLength(RT.java:1128) 在clojure.lang.RestFn.applyTo(RestFn.java:135) 在clojure.core $ apply__4370.invoke(core.clj:438) 在clojure.core $ resultset_seq_ 6276 $ thisfn _6290 $ fn__6291.invoke(core.clj:3842) 在clojure.lang.LazySeq.sval(LazySeq.java:42) ... 8更多引起:java.sql.SQLException:用尽 结果集 at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146) at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208) at oracle.jdbc.driver.OracleResultSetImpl.getObject(OracleResultSetImpl.java:900) 在clojure.core $ resultset_seq__6276 $ row_values_ 6284 $ fn _6286.invoke(core.clj:3839) 在clojure.core $ map_ 5053 $ fn _5055.invoke(core.clj:1760) 在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))
答案 0 :(得分:3)
不要使用def
- 顶层的所有内容都是在类加载时(或甚至在编译时)执行的,因此在运行{{1}之前关闭结果集(rs
) }。始终在单个功能中打开和关闭连接 - 它可以防止很多错误。
另请考虑使用clojure.contrib.sql。很好的例子可以在wikibooks找到。
对于这两种方法,不要忘记使用-main
来表示任何可能的延迟序列。
答案 1 :(得分:0)
我接受了Andrei的建议并使用了clojure.contrib.sql。它确实使这更简单,更不容易出错。我仍然不想放弃db和sql全局变量的def。
感谢Andrei
(ns my.query (:use [clojure.contrib.sql]))
(def *db* {:classname "oracle.jdbc.driver.OracleDriver" ; must be in classpath
:subprotocol "oracle:thin"
:subname "myserver:1521:mydatabase"
; Any additional keys are passed to the driver
; as driver-specific properties.
:user "account"
:password "password" })
(def *sql* "select * from phonebook")
(defn dump-db-csv []
(with-connection *db*
(transaction
(with-query-results rs [*sql*]
(doseq [row rs] ;; for all rows
(doseq [[key value] row] ;; for all fields
(if (= key :phone) ;; if last field
(print (.trim (str value))) ;; do not print comma
(print (format "%s%s" (.trim (str value)) ","))))
(println))))))
;; Main - call the function to print rows
(dump-db-csv)