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 而不是服务名称时不连接的主要内容,如果未能解决你的问题,请参考以下文章
Linux下使用Python连接Oracle 报cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be lo