Clojure的cx_Oracle-like包

时间:2014-02-14 17:08:27

标签: python oracle jdbc clojure

我来自一个非常繁重的Python-> Oracle开发环境,并且一直在玩Clojure。我喜欢cx_Oracle带给我的Python端数据库的易用性,并且想知道Clojure是否有类似的东西。

具体而言,我正在寻找的是让我轻松访问数据库连接,ala cx_Oracle的“用户名/密码@tns_name”格式。

到目前为止,我提出的最好的是:

(defn get-datasource [user password server service]
    {:datasource (clj-dbcp.core/make-datasource {:adapter :oracle
                                               :style :service-name
                                               :host server
                                               :service-name service
                                               :user user
                                               :password password})})

这需要服务器,但95%的用户不知道他们正在点击什么服务器,只知道来自tnsnames.ora的tns名称。

此外,我不知道何时有数据库连接以及何时断开连接。使用cx_Oracle,我必须执行with cx_Oracle.connect()...connection.close()才能关闭连接。

有人可以就连接的数据源如何工作以及给定用户名,密码和tns别名连接数据库的最简单方法向我提供指导吗?

谢谢!

1 个答案:

答案 0 :(得分:3)

最好使用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驱动程序同时具有精简和OCI JDBC连接选项。

要与名为TNS的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 in语句。它创建一个连接并将其添加到var。其他语句将使用该连接。在基于其他查询的结果创建动态查询时,这尤其方便。

同样适用于with-db-transaction。它具有与with-db-connection相同的语义,但是这里的范围不仅保证使用相同的连接,而且通过将它们包装在事务块中,所有语句或者都不成功。 with-db-connectionwith-db-transaction都可以嵌套。

还有更多高级选项,例如创建连接池而不是query等。创建或重用单个连接,让它们从池中绘制连接。有关这些内容,请参阅clojure-doc.org documentation