nkjmkzk.net

powered by Kazuki Nakajima

pythonからOracleに接続するための拡張モジュール、cx_Oracleの基本的な使い方

cx_Oracleはそこそこ本格的な機能を提供してくれるOracle Database接続用のpythonモジュールです。phpのoci8と比較してもデータベースインスタンスを停止/起動するためのPRELIM AUTHモードをサポートしていたり、マルチスレッドで動かすためのTHREADEDモードをサポートしていたりとかゆいところに手が届きます。

このエントリではごく一般的な操作を解説します。データベース及びInstant Clientのバージョンは11g Release 2 x86_64とします。

インストールについてはこちらのエントリを。pythonからOracleに接続するための拡張モジュール、cx_Oracleのインストール方法

cx_Oracleをpythonスクリプト中で使うにはまずcx_Oracleをインポートします。

#!/usr/bin/python

import cx_Oracle

実行時に下記のエラーが出る場合は$LD_LIBRARY_PATHが通っていない可能性があります。

ImportError: libclntsh.so.11.1: cannot open shared object file: No such file or directory

Oracle Instant Clientを利用している場合は/usr/lib/oracle/11.2/client64/libにライブラリがありますので下記のように$LD_LIBRARY_PATHを通します。

[oracle@~]$ export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib

まずは接続。個人的にはこれが一番難解なのではと思っています(マジでか)。僕がいつも使っている接続はこの形式です。

conn = cx_Oracle.connect('scott', 'tiger', '172.22.0.54/orcl.kawasaki.nkjmkzk.com')

* scott => ユーザ名
* tiger => パスワード
* 172.22.0.54 => データベースのIPアドレスまたはホスト名 RACの場合にインスタンスを指定する必要がなければSCANを指定
* orcl.kawasaki.nkjmkzk.com => データベースのサービス

ややこしいのが3つ目の172.22.0.54/orcl.kawasaki.nkjmkzk.comの部分。この引数はいろいろなフォーマットがありますが、僕はこのEasy Connectと呼ばれるフォーマットを好んでいます。一般にはtnsnames.oraに定義したエントリ名を使用する方がポピュラーでスクリプト自体は簡素にはなりますが、事前にtnsnames.oraを定義しなければいけないですし、tnsnames.oraがサーチパス上に配置されていなくてはならないのでその部分が汎用的でない気がして僕はあまり使いません。

データベースのIPアドレスまたはホスト名にSCANを使用する場合はデータベースノード上でsrvctlで確認できます。

[oracle@~]$ srvctl config scan
SCAN name: orcl-scan, Network: 1/172.22.0.0/255.255.252.0/eth0
SCAN VIP name: scan1, IP: /orcl-scan.kawasaki.nkjmkzk.com/172.22.0.56

サービスもsrvctlコマンドで確認できます。unique nameとdomainを合わせたものがデフォルトのサービスとなります。

[oracle@~]$srvctl config database -d orcl | grep -e 'Database unique name:' -e 'Domain:'
Database unique name: orcl
Domain: kawasaki.nkjmkzk.com

* orcl.kawasaki.nkjmkzk.comがサービス名となる

明示的に作成したサービスは下記のsrvctlコマンドで確認できます。

[oracle@~]$ srvctl config service

また、上記はノーマルユーザでの接続でしたが、管理作業を行うためにSYSDBAとして接続する場合は次のようにcx_Oracle.SYSDBAフラグを立てます。

conn = cx_Oracle.connect('sys', 'secret', '172.22.0.54/orcl.kawasaki.nkjmkzk.com', cx_Oracle.SYSDBA)

さらに例外処理をきちんと行う場合は下記のようにtry:配下に置き、cx_Oracle.DatabaseErrorの例外を拾うようにします。

try:
    conn = cx_Oracle.connect('scott', 'tiger', '172.22.0.54/orcl.kawasaki.nkjmkzk.com')
except cx_Oracle.DatabaseError,cx_msg:
    print "[ERROR] Failed to connect to Database."
    print "[ERROR cx_Oracle] %s" % cx_msg

* エラーメッセージがcx_msgに代入される

これでデータベースへのセッションが確立されました。次にデータベースに命令を発行しています。
まずはテーブルを作成してみましょう。

先ほど作成したコネクションオブジェクトからカーソルオブジェクトを作成します。これは呪文だと思って実行してください。

cur = conn.cursor()

SQL文を定義してexecute()を発行すればSQL文がデータベースで実行されます。ちなみにSQL文は末尾にセミコロンを入れてはいけません。

sql = "CREATE TABLE TEST_TABLE (COL1 NUMBER)"
cur.execute(sql)

こちらも例外処理を行うには下記のようにtry:配下に置きます。

sql = "CREATE TABLE TEST_TABLE (COL1 NUMBER, COL2 VARCHAR(64))"
try:
    cur.execute(sql)
except cx_Oracle.DatabaseError,cx_msg:
    print "[ERROR] Failed to execute SQL: " + sql
    print "[ERROR cx_Oracle] %s" % cx_msg

データを3件ほどインサートします。デフォルトでは自動でコミットされません。明示的にconn.commit()でコミットする必要があります。

sql = "INSERT INTO TEST_TABLE VALUES (1, 'apple')"
cur.execute(sql)
sql = "INSERT INTO TEST_TABLE VALUES (2, 'orange')"
cur.execute(sql)
sql = "INSERT INTO TEST_TABLE VALUES (2, 'lemon')"
cur.execute(sql)
conn.commit()

データを取得します。データの取得には主にfetchall(), fetchmany(), fetchone()のいずれかを使うことになると思いますが、ここではfetchallを使用しています。fetchallは全検索結果を行を一つのタプルとしてその配列を返します。

sql = "SELECT * FROM TEST TABLE"
cur.execute(sql)
rows = cur.fetchall()
for row in rows:
    print row[0],
    print row[1]

とりあえずここで紹介したメソッドが使えればアプリケーションで求められる基本的な操作はカバーできてしまうかも。

without comments

Written by 中嶋 一樹

5月 29th, 2011 at 1:11 pm

Posted in Uncategorized

Tagged with , ,

Leave a Reply