cx_Oracle 在连接字符串上使用 SID 而不是服务名称时不连接

Posted

技术标签:

【中文标题】cx_Oracle 在连接字符串上使用 SID 而不是服务名称时不连接【英文标题】:cx_Oracle doesn't connect when using SID instead of service name on connection string 【发布时间】:2014-07-31 16:43:32 【问题描述】:

我有一个像这样的连接字符串

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,但不适用于服务名称)

Using Oracle Service Names with SQLAlachemy Oracle SID and Service name; connection problems cx_Oracle & Connecting to Oracle DB Remotely

使用cx_Oracle、使用SID 而不是服务名称连接到Oracle 的正确方法是什么?如何在无需调整 TNSNAMES.ORA 文件的情况下执行此操作?我的应用程序在内部分发给许多用户,在处理在 Windows 计算机上没有管理员权限的用户时,对 TNSNAMES 文件进行更改并不理想。此外,当我使用服务名称时,我根本不需要触摸这个文件,并希望它保持这种状态。

【问题讨论】:

【参考方案1】:

我曾一度认为我将无法使用 Magic SQL(%sql%%sql),因为连接中的服务名称问题会强制使用上述 cx_Oracle.connect() 的替代方式, cx_Oracle.makedsn()... 我终于找到了一个适合我的解决方案:首先为服务名称声明并设置一个变量,然后在命令中使用它(因为如果将服务名称的文字字符串放入命令中将不起作用!)

import cx_Oracle

user='youruser'
pwd='youruserpwd'
dbhost='xx.xx.xx.xx'
service='yourservice'

%load_ext sql
%sql oracle+cx_oracle://$user:$pwd@$dbhost:1521/?service_name=$service

输出(连接成功后得到的):

u'Connected: youruser@'

【讨论】:

【参考方案2】:

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

【讨论】:

【参考方案3】:

如果您使用的是 sqlalchemy 和 ORACLE 12,以下似乎可以工作。

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

注意,您必须使用服务名称而不是 SID。我不知道为什么,但是使用 SID 的简单连接字符串不起作用。

【讨论】:

【参考方案4】:

对于那些寻找如何指定 service_name 而不是 SID 的人。

来自changelog,用于 SQLAlchemy 1.0.0b1(2015 年 3 月 13 日发布):

[oracle] [feature] 添加了对 cx_oracle 连接到 特定的服务名称,而不是 tns 名称,通过传递 ?service_name=<name> 到 URL。拉请求由 Sławomir 提供 埃勒特。

此更改引入了新的 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而不是sqlalchemy的问题【参考方案5】:

我也遇到了这个问题。 解决办法是:

1: get the service name at tnsnames.ora
2: put the service name in
con_str = "myuser/mypass@oracle.sub.example.com:1521/ora1"

【讨论】:

【参考方案6】:

它仍然可能无法正常工作。您需要获取 dsnStr 的输出并通过将 SID 替换为 SERVICE_NAME 来修改字符串,并在 con 字符串中使用该变量。这个过程对我有用。

【讨论】:

【参考方案7】:

在一个类似的场景中,我能够通过使用cx_Oracle.makedsn() 创建一个带有给定SID(而不是服务名称)的 dsn 字符串来连接到数据库:

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()

【讨论】:

文档很清楚。只需执行cx_Oracle.makedsn("oracle.sub.example.com", "1521", service_name="ora1"),显式使用关键字service_name 将其与第三个参数(即sid)区分开来。 非常有用,经过 2 天的搜索后登陆这里,不到 30 秒就奏效了。了不起。非常感谢@Andreas Fester。 @S4nd33p 谢谢,很高兴听到它有帮助:-) 经过一个月的搜索,并使用了不同种类的目录和环境变量,这就是最终让我连接到服务器并开始拉数据的答案。很不错

以上是关于cx_Oracle 在连接字符串上使用 SID 而不是服务名称时不连接的主要内容,如果未能解决你的问题,请参考以下文章

python cx_Oracle 游标不返回有效查询的行

Linux下使用Python连接Oracle 报cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be lo

在 cx_Oracle 中跨 Oracle Schema 进行查询

cx_Oracle连接数据库总结

不安装Oracle使用cx_Oracle

python -- 连接 orclae cx_Oracle的使用