sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-12505: TNS: 監聽程序當前無法識別連接描述符中所給出的 SID


主要原因可能是目標數據庫是集群部署,可以咨詢一下DBA

python 用sqlalchemy 連接Oracle數據庫的時候報了下面這個錯誤:

sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-12505: TNS: 監聽程序當前無法識別連接描述符中所給出的 SID
(Background on this error at: http://sqlalche.me/e/4xp6)

這是因為 sqlalchemy 在create_engine的時候默認是調用cx_Oracle去連接數據庫,而cx_Oracle 在創建dns連接字符串的時候是默認SID = tnsname (實例名),其實是在連接的時候調用了 cx_Oracle.makedns 來構造連接url,我們通過下面的例子來看

In[95]: import cx_Oracle
In[96]: cx_Oracle.makedsn('10.24.04.19', '1314', 'report')
Out[96]: '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.24.04.19)(PORT=1314))(CONNECT_DATA=(SID=report)))'
In[97]: cx_Oracle.makedsn('10.24.04.19', '1314', service_name='report')
Out[97]: '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.24.04.19)(PORT=1314))(CONNECT_DATA=(SERVICE_NAME=report)))'

  因為cx_Oracle不會去讀我們配置的tnsname.ora文件,而是通過傳進去的參數來構造連接url
所以如果不指定service_name,那么這個函數就會默認將 ‘report’ 視為 SID (positional args),這樣做的話對於單機部署的 Oracle數據庫是沒有問題的,但是如果目標數據庫是集群部署的話,就會出現ORA-12505: TNS: 監聽程序當前無法識別連接描述符中所給出的 SID 的情況。
更深入的解釋可以看下面
  由於oracle 是做的多節點,然后有一個公用的service_name,只有通過service_name去連接才能起到負載均衡的作用,而以cx_Oracle默認的連接串去連的話只能連接到實例名,而不能連接到service_name,所以oracle用service_name去匹配實例名,當然找不到。所以連接時必須指定連的是service_name而不是sid.


所以我們需要修改連接字符串,SQLAlchemy 連接方式:

import cx_Oracle
from sqlalchemy import create_engine
ip = '10.24.04.19'
port = '1314'
uname = 'jiajia' # 用戶名
pwd = 'yupeng' # 密碼
tnsname = 'report' # 實例名

dsnStr = cx_Oracle.makedsn(ip, port, service_name=tnsname)
connect_str = "oracle://%s:%s@%s" %(uname, pwd, dsnStr)
engine = create_engine(connect_str, encoding=encoding)

cx_Oracle連接方法:

conn = cx_Oracle.connect(uname, pwd, dsn=dsnStr)




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM