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