cx_oracle 12505,sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-12505: TNS: 监听程序当前无法识别连接...

sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-12505: TNS: 监听程序当前无法识别连接描述符中所给出的 SID

主要原因可能是目标数据库是集群部署, 可以咨询一下 DBA

python 用 sqlalchemy 连接 Oracle 数据库的时候报了下面这个错误:

(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]:importcx_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 连接方式:importcx_Oracle

fromsqlalchemyimportcreate_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:%[email protected]%s"%(uname,pwd,dsnStr)

engine=create_engine(connect_str,encoding=encoding)

cx_Oracle 连接方法:

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

来源: http://www.bubuko.com/infodetail-3097395.html

你可能感兴趣的:(cx_oracle,12505)