最好用 Clojure 最惯用的数据库库clojure.java.jdbc。
首先,由于 maven 存储库中没有 Oracle 驱动程序,我们需要下载最新的驱动程序并将其安装到我们的本地存储库中,使用 lein-localrepo 插件:
lein localrepo install -r D:\Path\To\Repo\
D:\Path\To\ojdbc6.jar
oracle.jdbc/oracledriver "12.1.0.1"
现在我们可以在 project.clj 中引用它,以及 clojure.java.jdbc。
(defproject oracle-connect "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/java.jdbc "0.3.3"]
[oracle.jdbc/oracledriver "12.1.0.1"]])
启动 REPL 后,我们可以通过默认主机/端口/SID 连接连接到数据库
(ns oracle-connect
(:require [clojure.java.jdbc :as jdbc]))
(def db
{:classname "oracle.jdbc.OracleDriver"
:subprotocol "oracle:thin"
:subname "//@hostname:port:sid"
:user "username"
:password "password"}))
(jdbc/query db ["select ? as one from dual" 1])
db 只是一个基本映射,称为 db-spec。这不是真正的联系,但具有建立联系所需的所有信息。 Clojure.java.jdbc 在需要时生成一个,例如在(query db ..) 中。
我们需要手动输入类名,因为 clojure.java.jdbc 在 Oracle 的子协议和类名之间没有默认映射。这可能是因为 Oracle JDBC 驱动程序同时具有瘦 JDBC 和 OCI JDBC 连接选项。
要与 TNS 命名数据库建立连接,驱动程序需要 tnsnames.ora 文件的位置。这是通过设置一个名为 oracle.net.tns_admin 的系统属性来完成的。
(System/setProperty "oracle.net.tns_admin"
"D:/oracle/product/12.1.0.1/db_1/NETWORK/ADMIN")
设置完成后,我们所需要的 subname 就是数据库的 tnsname。
(def db
{:classname "oracle.jdbc.OracleDriver"
:subprotocol "oracle:thin"
:subname "@tnsname"
:user "username"
:password "password"}))
(jdbc/query db ["select ? as one from dual" 1])
现在进入“连接如何工作”部分。如前所述,clojure.java.jdbc 在需要时创建连接,例如在查询函数中。
如果您只想转换查询结果,您可以提供两个额外的可选命名参数::row-fn 和 :result-set-fn。每一行都用 row-fn 转换,然后整个结果集用 result-set-fn 转换。
这两者都是在连接的上下文中执行的,因此在执行所有这些操作之前,保证连接是打开的,除非这些函数返回惰性序列。
默认情况下 :result-set-fn 被定义为doall 保证实现所有结果,但如果你重新定义它一定要实现所有惰性结果。通常,每当您在使用范围之外的结果时遇到连接或结果集关闭异常时,问题就是您没有。
连接只存在于query 函数的范围内。最后它是关闭的。这意味着每个查询都会产生一个连接。如果您想在一个连接中完成多个查询,可以将它们包装在 with-db-connection 中:
(jdbc/with-db-connection [c db]
(doall (map #(jdbc/query c ["select * from EMP where DEPTNO = ?" %])
(jdbc/query c ["select * from DEPT"] :row-fn :DEPTNO))))
在with-db-connection 绑定中,您将 db-spec 绑定到一个 var,并在绑定范围内的语句中使用该 var 而不是 db-spec。它创建一个连接并将其添加到 var。其他语句将使用该连接。这在根据其他查询的结果创建动态查询时特别方便。
with-db-transaction 也是如此。它与with-db-connection 具有相同的语义,但是这里的作用域不仅保证使用相同的连接,而且通过将它们包装在事务块中来保证所有语句或不成功。 with-db-connection 和 with-db-transaction 都是可嵌套的。
还有更高级的选项,例如创建连接池,而不是 query 等。创建或重用单个连接,让它们从池中绘制连接。有关这些,请参阅clojure-doc.org documentation。