cx_Oracle-подобный пакет для Clojure

2

Я прихожу из очень тяжелой 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% моих пользователей не знают, на каком сервере они попадают, просто имя tns из tnsnames.ora.

Кроме того, я не понимаю, когда у меня есть соединение с базой данных и когда оно отключается. С cx_Oracle я либо должен был сделать with cx_Oracle.connect()... или connection.close() чтобы закрыть соединение.

Может ли кто-нибудь дать мне рекомендации относительно того, как работают источники данных, и насколько проще всего подключиться к базе данных с учетом имени пользователя, пароля и псевдонимов tns?

Благодарю!!

Теги:
jdbc
clojure

1 ответ

3
Лучший ответ

Лучше всего использовать Clojure самую идиоматическую библиотеку баз данных clojure.java.jdbc.

Во-первых, поскольку драйвер Oracle недоступен из репозитория maven, нам нужно загрузить последнюю версию и установить ее в нашем локальном репозитории, используя плагин lein-localrepo:

lein localrepo install -r D:\Path\To\Repo\
                          D:\Path\To\ojdbc6.jar
                          oracle.jdbc/oracledriver "12.1.0.1"

Теперь мы можем ссылаться на него в нашем проекте.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 делает один, когда это необходимо, например in (query db..).

Нам нужно ввести имя класса вручную, потому что clojure.java.jdbc не имеет сопоставления по умолчанию между подпротоколом и именем класса для Oracle. Вероятно, это связано с тем, что драйвер JDBC Oracle имеет как тонкие, так и 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 создает соединения, когда это необходимо, например, в функции запроса.

Если все, что вы хотите сделать, это преобразовать результаты запроса, вы можете :result-set-fn два дополнительных необязательных именованных параметра :row-fn и :result-set-fn. Каждая строка преобразуется в строку-fn, после чего весь набор результатов преобразуется с помощью результата-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 -db with-db-transaction являются вложенными.

Существуют также более продвинутые параметры, такие как создание пулов соединений, а не query и др. создавать или повторно использовать отдельные соединения, заставить их нарисовать соединение из пула. См. Документацию clojure-doc.org.

  • 0
    ВАУ, я должен сказать, что это один из лучших и самых подробных ответов, которые я когда-либо читал на stackoverflow. При этом мне потребуется некоторое время, чтобы переварить и проверить это, а затем я приму это как ответ. Огромное спасибо!!
  • 0
    Итак, я не могу подключиться. С: subname "@tnsalias" я получаю сообщение об ошибке: java.sql.SQLRecoverableException: ошибка ввода-вывода: указан неизвестный хост Если я использую: subname "tnsalias", я получаю сообщение об ошибке: java.sql.SQLRecoverableException: ошибка ввода-вывода: сеть Адаптер не может установить соединение, которое я могу tnsping базы данных с tnsalias, поэтому я знаю, что проблема в конце clojure / java / etc.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню