ALGOBIT > 離散的な気まぐれ

2011/09/06

clojure から DBMS を利用する

Filed under: 離散的な気まぐれ — タグ: , , , , , , , — Kohyama @ 14:11

準備

アクセスしたい DBMS 製品の JDBC ドライバを取得し,
JRE が標準でサーチする外部クラスライブラリの配置場所に加えます.

Oracle の場合は, このへん (Oracle 10g の場合) から,
MySQL の場合は, このへん から,
PostgreSQL の場合は, このへん から,
JRE (もしくは JDK) のバージョンおよび, DBMS 製品のバージョンに適合するバージョンのJDBCドライバファイル (大抵は zip か jar でアーカイブされた単一のファイル) を入手します.

Windows の場合は, C:\Program Files\Java\jre6\lib\ext (JRE 1.6 の場合) あたり,
Linux の場合は, /usr/lib/jvm/java-6-sun/jre/lib/ext/ (Ubuntu の場合) あたり,
MacOS X の場合は, /Library/Java/Extensions/ あたり,
に上記 zip または jar ファイルとして入手した JDBC ドライバをコピーします.

もちろん, DBMS がローカルにインストールされており, JDBCドライバが既に存在するのでコピーしたくないとか, 現在のプロジェクトを管理するフォルダ階層の下に置いておきたい,
などの理由で標準サーチパスに置きたくない場合は, クラスパスにドライバファイルへの絶対パスもしくは相対パスを追加しても構いません.

最小限

データベースアクセスに必要な最低限の記述を部品化せず全て展開した状態で書くと
以下のようになります.

(use 'clojure.contrib.sql)
(with-connection {:classname "oracle.jdbc.OracleDriver"
                  :subprotocol "oracle"
                  :subname "thin:@${HOST}:${PORT}:${SID}"
                  :user "${USER}"
                  :password "${PASSWORD}"}
  ; ここでの記述はデータベース ${HOST}, ${PORT}, ${SID}
  ; に対するトランザクションの中で実行される.
  (with-query-results rs [${QUERY}]
    ; ここでの記述はデータベースに対する ${QUERY} の実行結果
    ; を rs にシーケンスとして束縛した状態で行われる
    ))

${HOST}, ${PORT}, ${SID} にアクセスしたいデータベースに関する情報,
${USER}, ${PASSWORD} にそのデータベースアクセスするアカウントの情報,
${QUERY} には発行したい SQL 文,
でそれぞれを直接置き換えてください.

MySQL の場合は

    :classname “com.mysql.jdbc.Driver”
    :subprotocol “mysql”
    :subname “//${HOST}:${PORT}/${SID}”

とします.

PostgreSQL の場合は

    :classname "org.postgresql.Driver"
    :subprotocol "postgresql"
    :subname "//${HOST}:${PORT}/${SID}"

とします.

結果セットに対して, トランザクション内で作業するのではなく,
ベクタとして取り出してしまいたい場合は,
with-query-results の本体で (into [] rs) とすれば OK.

例えば

IP アドレス 192.168.1.1 で稼働する, ポート 1521 でアクセス可能な Oracle に,
パスワード PaSsWoRd の kohyama というユーザがあり,
kohyamadb というインスタンスへの select 権限があるとします.
JRE 1.6 (ともちろん clojure) のインストールされた Windows から, kohyamadb のテーブル一覧を見るには
上記サイトからダウンロードした classes12.jar を
C:\Program Files\Java\jre6\lib\ext\ にコピーし

(use 'clojure.contrib.sql)
(with-connection {:classname "oracle.jdbc.OracleDriver"
                  :subprotocol "oracle"
                  :subname "thin:@192.168.1.1:1521:kohyamadb"
                  :user "kohyama"
                  :password "PaSsWoRd"}
  (with-query-results rs ["select * from all_tables"]
    (into [] rs)))

とします.
簡単過ぎる...

部品化例

私の場合はこんな風にして使いました.

(use 'clojure.contrib.sql)
(defn db [& {:keys [dbms host port sid user password]}]
  (conj
    (cond
      (= dbms "oracle")
        {:classname "oracle.jdbc.OracleDriver"
         :subprotocol "oracle"
         :subname (str "thin:@" host ":" port ":" sid)}
      (= dbms "mysql")
        {:classname "com.mysql.jdbc.Driver"
         :subprotocol "mysql"
         :subname (str "//" host ":" port "/" sid)}
      (= dbms "postgresql")
        {:classname "org.postgresql.Driver"
         :subprotocol "postgresql"
         :subname (str "//" host ":" port "/" sid)})
    {:user user
     :password password}))

(def con
  (db :dbms "oracle" :host "192.168.1.1" :port 1521 :sid "kohyamadb"
    :user "kohyama" :password "PaSsWoRd"))

(def all_tables
  (with-connection con
    (with-query-results rs ["select * from all_tables"]
      (into [] rs))))

(print all_tables)

関数 db は, DBMS 製品の名称, ホスト名, ポート, インスタンス名, ユーザ名,
パスワードをキーワード引数で渡すと,
with-connection に渡すべきマップを作成します.
19〜21行目で特定のDBに対する特定のアカウントでの接続用のマップを作成します.
23〜26 行目でトランザクションを実行し結果を取り出します.

Related Posts:

コメントをどうぞ

*

Copyright © 2010 Yoshinori Kohyama All Rights Reserved.