Python安裝cx_Oracle與操做數據測試小結

這裏簡單總結一下Python操做Oracle數據庫這方面的相關知識。只是簡單的整理一下以前的實驗和筆記。這裏的測試服務器爲CentOS Linux release 7.5. 我的實驗、測試、採集數據的一臺機器。html

1:安裝cx_Oracle

這裏簡單介紹一下cx_Oracle,下面一段內容摘自cx_Oracle的做者(Anthony Tuininga )的一篇博文,詳情參考https://www.oracle.com/technetwork/cn/topics/tuininga-cx-oracle-086962-zhs.htmlpython

cx_Oracle是一個Python 擴展模塊,經過使用全部數據庫訪問模塊通用的數據庫 API來實現 Oracle 數據庫的查詢和更新。爲使用一些專爲 Oracle 設計的特性,還加入了多個通用數據庫 API 的擴展。cx_Oracle 的開發歷時十多年,涵蓋了大多數須要在 Python 中訪問 Oracle 的客戶的需求。2008 年 12 月,一個新的主要版本解決了早期版本的衆多限制,並增添了對 Python 3.0 和 Oracle 新推出的一些特性的支持。linux

cx_Oracle的官方文檔:https://cx-oracle.readthedocs.io/en/latest/# 官方文檔從架構、特徵方面介紹了cx_Oracle,簡單摘錄以下所示:ios

Architecture

Python programs call cx_Oracle functions. Internally cx_Oracle dynamically loads Oracle Client libraries to access Oracle Database.nginx

cs_Oracle

Fig. 1 cx_Oracle Architecture
cx_Oracle is typically installed from PyPI using pip. The Oracle Client libraries need to be installed separately. The libraries can be obtained from an installation of Oracle Instant Client, from a full Oracle Client installation, or even from an Oracle Database installation (if Python is running on the same machine as the database).git

Features

The cx_Oracle feature highlights are:github

  • Easily installed from PyPI
  • Support for Python 2 and 3, and for multiple Oracle Database versions
  • Execution of SQL and PL/SQL statements
  • Extensive Oracle data type support, including large objects (CLOB and BLOB) and binding of SQL objects
  • Connection management, including connection pooling
  • Oracle Database High Availability features
  • Full use of Oracle Network Service infrastructure, including encrypted network traffic and security features
    A complete list of supported features can be seen here.

下面介紹安裝cx_Oracle,cx_Oracle組件有多種安裝方式,實在想不出不用pip安裝的理由,由於它實在太簡單、方便了!web

pip install cx_Oracle

[root@db-server ~]# pip install cx_Oracle
Collecting cx_Oracle
  Downloading https://files.pythonhosted.org/packages/ff/95/6c50d13da95de3e438e7d333dbd7b0946a0981c778e8153c73061b018a33/cx_Oracle-7.2.3-cp36-cp36m-manylinux1_x86_64.whl (731kB)
     |████████████████████████████████| 737kB 295kB/s 
Installing collected packages: cx-Oracle
Successfully installed cx-Oracle-7.2.3

安裝成功後,測試驗證sql

[root@db-server ~]# python
Python 3.6.6 (default, Sep 20 2019, 08:20:38
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help""copyright""credits" or "license" for more information.
>>> import cx_Oracle
>>

2:安裝Oracle客戶端

這裏咱們打算安裝Oracle Instant Client,能夠去下面官方網址選擇正確的、所需的版本。本次實驗,我選擇了instantclient-basic-linux.x64-11.2.0.4.0.zipshell

https://www.oracle.com/database/technologies/instant-client/downloads.html
https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html

這裏下載的Oracle Instant Client Zip,安裝過程簡單以下:

1:解壓安裝包文件到指定目錄

 mkdir -p /opt/oracle
 cd /opt/oracle/
 mv instantclient-basic-linux.x64-11.2.0.4.0.zip  /opt/oracle/
 unzip instantclient-basic-linux.x64-11.2.0.4.0.zip 

2:在操做系統安裝libaio package,不然有可能在運行python腳本時遇到錯誤提示「ImportError: libaio.so.1: cannot open shared object file: No such file or directory」

yum install libaio

注意:這個不是必須的,有些狀況下會遇到這個錯誤。

3:將Instant Client永久添加到運行時連接路徑

 sudo sh -c "echo /opt/oracle/instantclient_11_2  > /etc/ld.so.conf.d/oracle-instantclient.conf"
 sudo  ldconfig #

或者將環境變量LD_LIBRARY_PATH設置爲Instant Client版本的相應目錄。

# echo $LD_LIBRARY_PATH
/usr/local/hadoop/lib/native

在/etc/profile中加入
export LD_LIBRARY_PATH=/opt/oracle/instantclient_11_2:$LD_LIBRARY_PATH

#
 source /etc/profile
# echo $LD_LIBRARY_PATH
/opt/oracle/instantclient_11_2:/usr/local/hadoop/lib/native

mkdir -p /opt/oracle/instantclient_11_2/network/admin

其它平臺的安裝(或者RPM安裝), 官方文檔https://oracle.github.io/odpi/doc/installation.html#linux 有詳細介紹,這裏就不多此一舉。 RPM的安裝也很簡單,以下所示

#rpm -ivh oracle-instantclient19.3-basic-19.3.0.0.0-1.x86_64.rpm 
Preparing...                ########################################### [100%]
   1:oracle-instantclient19.########################################### [100%]

須要注意的是,安裝是必須版本一致:cx_Oracle、Oracle Client、Python最好一致,不然就會出現不少問題,例以下面這些(學習、測試中遇到的錯誤)

1:cx_Oracle 報錯:cx_Oracle.DatabaseError: DPI-1050: Oracle Client library must be at version 11.2
2:cx_Oracle.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "/lib64/libc.so.6: version `GLIBC_2.14' not found (required by /usr/lib/oracle/19.3/client64/lib/libclntsh.so)". See https://oracle.github.io/odpi/doc/installation.html#linux for help

ORACLE的鏈接方式

cx_Oracle鏈接ORACLE數據庫的鏈接字符串(Connection Strings)有多種方式,下面簡單整理一下:

首先,咱們能夠看看cx_Oracle.connect這個函數的參數以下:

cx_Oracle.connect(user=None, password=None, dsn=None, mode=cx_Oracle.DEFAULT_AUTH, handle=0, pool=None, threaded=False, events=False, cclass=None, purity=cx_Oracle.ATTR_PURITY_DEFAULT, newpassword=None, encoding=None, nencoding=None, edition=None, appcontext=[], tag=None, matchanytag=None, shardingkey=[], supershardingkey=[])

參數看起來至關多,眼花繚亂的。不過沒有關係,其實你用到的很少,不少參數基本上能夠選擇性忽略。比較經常使用的基本上有下面幾個:

user 用戶名
password 密碼
dsn dsn
encoding 編碼

Easy Connect Syntax for Connection Strings

dbhost.example.com是機器名,也能夠數據庫服務器IP地址,orclpdb1是service names, 注意,這種方式不能使用早期的SID

import cx_Oracle

# Obtain password string from a user prompt or environment variable
userpwd = ". . ." 

connection = cx_Oracle.connect(username, userpwd, "dbhost.example.com/orclpdb1", encoding="UTF-8")

若是數據庫不是默認的端口號,那麼須要在鏈接字符串中指定端口號,以下所示:

connection = cx_Oracle.connect(username, userpwd, "dbhost.example.com:1984/orclpdb1",
        encoding="UTF-8")

Oracle Net Connect Descriptor Strings

介紹這種鏈接字符串方式前,咱們必須先了解一下函數makedns,它的功能是建立一個dns對象, 以下所示:

cx_Oracle.makedns
( host
, port
, sid=None
, service_name=None
, region=None
, sharding_key=None
, super_sharding_key=None)

dsn = cx_Oracle.makedsn("dbhost.example.com"1521, service_name="orclpdb1")
connection = cx_Oracle.connect(username, userpwd, dsn, encoding="UTF-8")
 另外,你也能夠用建立相似的鏈接描述符字符串,以下所示:
dsn = """(DESCRIPTION=
             (FAILOVER=on)
             (ADDRESS_LIST=
               (ADDRESS=(PROTOCOL=tcp)(HOST=sales1-svr)(PORT=1521))
               (ADDRESS=(PROTOCOL=tcp)(HOST=sales2-svr)(PORT=1521)))
             (CONNECT_DATA=(SERVICE_NAME=sales.example.com)))"""


connection = cx_Oracle.connect(username, userpwd, dsn, encoding="UTF-8")

Net Service Names for Connection Strings

這種鏈接字符串方式就不用多介紹了,基本上學習ORACLE的入門的時候,就已經瞭解了這方面的知識點

MyDB =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = xxxxx)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orclpdb1)
    )
  )

connection = cx_Oracle.connect(username, userpwd, "MyDB", encoding="UTF-8")

JDBC and Oracle SQL Developer Connection Strings

cx_Oracle鏈接字符串語法與Java JDBC和通用Oracle SQL Developer語法不一樣,通常JDBC的鏈接字符串以下:

jdbc:oracle:thin:@hostname:port/service_name、

cx_Oracle的方式以下:

connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com:1521/orclpdb1", encoding="UTF-8")

用戶名/密碼@Oracle服務器IP/Oracle的SERVICE_NAME")
db_conn=cx_Oracle.connect('test/test123456@10.20.57.24/GSP')

ORACLE的基本操做

下面簡單介紹一下使用cx_Oracle操做數據庫的一些簡單例子

ORACLE的查詢

簡單查詢
import cx_Oracle

db_conn=cx_Oracle.connect('test/test123456@10.20.57.24/gsp.localdomain')
db_cursor=db_conn.cursor()

sql_cmd='SELECT * FROM TEST.TEST'

db_cursor.execute(sql_cmd)


for row in  db_cursor:
    print(row)

db_cursor.close()
db_conn.close()

注意事項:SQL語句裏面不能加上分號(;)這類結束符,不然就會報 ORA-00911: invalid character錯誤:

若是上面SQL腳本里面多了一個分號,就會出現下面錯誤:

sql_cmd='SELECT * FROM TEST.TEST;'



[root@MyDB python]# python orace_select.py 
Traceback (most recent call last):
  File "orace_select.py", line 8in <module>
    db_cursor.execute(sql_cmd)
cx_Oracle.DatabaseError: ORA-00911: invalid character

帶參數查詢

import cx_Oracle

db_conn=cx_Oracle.connect("test""test123456""10.20.57.24/gsp.localdomain",encoding="UTF-8")
db_cursor=db_conn.cursor()

sql_cmd='SELECT * FROM TEST WHERE ID=:ID'
sql_p_id={'ID':100}

db_cursor.execute(sql_cmd,sql_p_id)


for row in  db_cursor:
    print(row)

db_cursor.close()
db_conn.close()

若是要獲取多行記錄,可使用fetchall函數。不用使用

import cx_Oracle

db_conn=cx_Oracle.connect("test""test123456""10.20.57.24/gsp.localdomain",encoding="UTF-8")
db_cursor=db_conn.cursor()

sql_cmd='SELECT * FROM TEST WHERE ID=:ID'
sql_p_id={'ID':100}

db_cursor.execute(sql_cmd,sql_p_id)

db_records= db_cursor.fetchall()
print(db_records)


db_cursor.close()
db_conn.close()

ORACLE的DML

其實對於INSERT、DELETE、UPDATE的操做,基本上差不不少。下面簡單簡單舉了一個UPDATE例子,沒有從細節和分類(UPDATE、INSERT、DELETE)展開。

#-*- coding: utf-8 -*-
import cx_Oracle

db_conn=cx_Oracle.connect("test""test123456""10.20.57.24/gsp.localdomain",encoding="UTF-8")
db_cursor = db_conn.cursor()

sql_cmd = 'INSERT INTO TEST.TEST(OWNER,OBJECT_ID,OBJECT_NAME)' \
          'VALUES(:OWNER, :OBJECT_ID, :OBJECT_NAME)'


db_cursor.execute(sql_cmd, ('TEST'1'KERRY1'))
db_cursor.execute(sql_cmd, ('TEST'2'KERRY2'))

db_conn.commit()

db_cursor.close()
db_conn.close()

注意,若是是插入多行記錄,你使用execute就會報以下錯誤:

cx_Oracle.NotSupportedError: Python value of type tuple not supported.

#-*- coding: utf-8 -*-
import cx_Oracle

db_conn=cx_Oracle.connect("test""test123456""10.20.57.24/gsp.localdomain",encoding="UTF-8")
db_cursor = db_conn.cursor()

sql_cmd = 'INSERT INTO TEST.TEST(OWNER,OBJECT_ID,OBJECT_NAME)' \
          'VALUES(:1, :2, :3)'

insert_record=[('TEST'1'KERRY1'),('TEST'2'KERRY2'),('TEST'3'KERRY3')]
db_cursor.bindarraysize =3
db_cursor.setinputsizes(30,int, 30)
#db_cursor.execute(sql_cmd, ('TEST'1'KERRY1'))
#db_cursor.execute(sql_cmd, ('TEST'2'KERRY2'))
db_cursor.execute(sql_cmd, insert_record)

db_conn.commit()

db_cursor.close()
db_conn.close()

正確的作法是使用executemany:

#-*- coding: utf-8 -*-
import cx_Oracle

db_conn=cx_Oracle.connect("test""test123456""10.20.57.24/gsp.localdomain",encoding="UTF-8")
db_cursor = db_conn.cursor()

sql_cmd = 'INSERT INTO TEST.TEST(OWNER,OBJECT_ID,OBJECT_NAME)' \
          'VALUES(:1, :2, :3)'

insert_record=[('TEST'1'KERRY1'),('TEST'2'KERRY2'),('TEST'3'KERRY3')]
db_cursor.bindarraysize =3
db_cursor.setinputsizes(30,int30)
db_cursor.executemany(sql_cmd, insert_record)

db_conn.commit()


db_cursor.close()
db_conn.close()

我的在總結的時候,發現官方文檔https://cx-oracle.readthedocs.io/en/latest/user_guide/sql_execution.html裏面的例子實在是太詳細了,這裏徹底沒有必要多此一舉。

參考資料:

https://cx-oracle.readthedocs.io/en/latest/index.html
https://github.com/oracle/python-cx_Oracle/tree/master/samples
https://blogs.oracle.com/oraclemagazine/perform-basic-crud-operations-using-cx-oracle-part-1
https://www.oracle.com/technetwork/articles/dsl/prez-python-queries-101587.html

相關文章
相關標籤/搜索