使用SID而非服务名时cx_Oracle无法连接

40 投票
8 回答
58998 浏览
提问于 2025-04-18 09:20

我有一个连接字符串,看起来像这样:

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 个回答

0

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)))")
0

这可能还是不行。你需要把dsnStr的输出结果拿出来,然后把字符串中的SID替换成SERVICE_NAME,接着在连接字符串中使用这个变量。这个方法对我有效。

4

如果你在使用sqlalchemy和ORACLE 12,下面的内容似乎可以正常工作。

from sqlalchemy import create_engine
con='oracle://user:password@hostname:1521/?service_name=DDDD'
engine = create_engine(con)

需要注意的是,你必须使用服务名称,而不是SID。我也不知道为什么,但使用SID的简单连接字符串是无法连接的。

7

对于那些想知道如何指定 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)
76

在类似的情况下,我通过使用 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()

撰写回答