使用SID而非服务名时cx_Oracle无法连接
我有一个连接字符串,看起来像这样:
con_str = "myuser/mypass@oracle.sub.example.com:1521/ora1"
其中 ora1
是我数据库的 SID。用这个信息在 SQL Developer 中连接是没问题的,也就是说我可以顺利连接并查询数据。
但是,如果我尝试用这个字符串连接到 Oracle,就会失败。
cx_Oracle.connect(con_str)
DatabaseError: ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
不过,如果 ora1
是服务名称,这个连接字符串格式就能正常工作。
我看到其他问题似乎和我的情况正好相反(用 SID 可以连接,但用服务名称却不行)。
那么,使用 cx_Oracle
连接到 Oracle 的正确方式是什么呢?我想用 SID
而不是服务名称。如何在不调整 TNSNAMES.ORA
文件的情况下做到这一点?我的应用程序要分发给很多内部用户,而对没有管理员权限的用户来说,修改 TNSNAMES
文件并不是个好主意。此外,当我使用服务名称时,我根本不需要碰这个文件,希望能保持这种状态。
8 个回答
SID(安全标识符)可能不容易找到,或者你的数据库可能根本就没有创建这个东西。
在我的情况下,我是在客户端请求访问一个云数据库,所以创建一个SID对我来说并没有什么意义。
相反,你可能会有一个看起来像这样的字符串:
"(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = something.cloud.company)
(PORT = 12345)) (ADDRESS = (PROTOCOL = TCP)(HOST = something.cloud.company)
(PORT = 12345)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME =
something.company)))"
你可以用这个字符串来替代SID。
connection = cx_Oracle.connect("username", "pw", "(DESCRIPTION = (ADDRESS =
(PROTOCOL = TCP)(HOST = something.cloud.company)(PORT = 12345)) (ADDRESS =
(PROTOCOL = TCP)(HOST = something.cloud.company)(PORT = 12345))
(CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = something.company)))")
这可能还是不行。你需要把dsnStr的输出结果拿出来,然后把字符串中的SID替换成SERVICE_NAME,接着在连接字符串中使用这个变量。这个方法对我有效。
如果你在使用sqlalchemy和ORACLE 12,下面的内容似乎可以正常工作。
from sqlalchemy import create_engine
con='oracle://user:password@hostname:1521/?service_name=DDDD'
engine = create_engine(con)
需要注意的是,你必须使用服务名称,而不是SID。我也不知道为什么,但使用SID的简单连接字符串是无法连接的。
对于那些想知道如何指定 service_name 而不是 SID 的人。
以下内容来自于 SQLAlchemy 1.0.0b1 的更新日志(发布于2015年3月13日):
[oracle] [功能] 增加了对 cx_oracle 连接特定服务名称的支持,而不是 tns 名称,只需在 URL 中添加
?service_name=<name>
。感谢 Sławomir Ehlert 的贡献。
这个变化引入了一个新的、特定于 Oracle 的选项 service_name
,可以用来构建连接字符串,格式如下:
from sqlalchemy import create_engine
from sqlalchemy.engine import url
connect_url = url.URL(
'oracle+cx_oracle',
username='some_username',
password='some_password',
host='some_host',
port='some_port',
query=dict(service_name='some_oracle_service_name'))
engine = create_engine(connect_url)
在类似的情况下,我通过使用 cx_Oracle.makedsn()
来创建一个 dsn 字符串,使用了给定的 SID
(而不是服务名称),成功连接到了数据库:
dsnStr = cx_Oracle.makedsn("oracle.sub.example.com", "1521", "ora1")
这会返回类似于
(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle.sub.example.com)(PORT=1521)))(CONNECT_DATA=(SID=ora1)))
的内容,然后可以用这个结果配合 cx_Oracle.connect()
来连接数据库:
con = cx_Oracle.connect(user="myuser", password="mypass", dsn=dsnStr)
print con.version
con.close()