使用SID而非服务名连接字符串时,cx_Oracle无法连接

40

我有一个连接字符串长这样

con_str = "myuser/mypass@oracle.sub.example.com:1521/ora1"

在这里,ora1是我的数据库的SID。在SQL开发人员中使用此信息可以正常工作,这意味着我可以连接并查询而无需遇到问题。

然而,如果我尝试使用此字符串连接Oracle,则会失败。

cx_Oracle.connect(con_str)

DatabaseError:  ORA-12514:  TNS:listener  does  not  currently  know  of  service  requested  in  connect  descriptor

如果ora1是一个服务名,那么这个连接字符串格式就可行。

我看到其他问题似乎与我的问题相反(它使用SID工作,但不使用服务名)

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

8个回答

76

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

5
文档非常清晰。只需使用关键字service_name明确区分第三个参数(即sid),执行以下命令:cx_Oracle.makedsn("oracle.sub.example.com", "1521", service_name="ora1") - dmvianna
2
非常有用,经过两天的搜索之后来到这里,只用了不到30秒就解决了问题。太棒了。非常感谢 @Andreas Fester。 - S4nd33p
仅仅一个点赞是不足以表达我的感激之情的。 - Catherine Devlin
整天都在弄明白为什么我无法写入到oracledb。有一些连接问题。这个10年前的答案真是救命稻草。运行得非常好!非常感谢@andreas!!! - undefined

7
对于那些想要指定服务名称而不是SID的人来说,以下是如何实现。
changelog中可以看出,SQLAlchemy 1.0.0b1(发布于2015年3月13日):

[oracle] [feature] 添加了对cx_oracle连接到特定服务名称(而不是tns名称)的支持,通过将?service_name=<name>传递给URL。感谢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)

1
这是关于 cx_Oracle 而不是 sqlalchemy 的问题。 - Superdooperhero

4
如果您正在使用SQLAlchemy和ORACLE 12,下面的方法似乎可以解决问题。
from sqlalchemy import create_engine
con='oracle://user:password@hostname:1521/?service_name=DDDD'
engine = create_engine(con)

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


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
如果有人想要设置oracle.jdbc.proxyClientName属性来使用代理客户端连接,他们可以使用cx_oracle。
cx_Oracle.init_oracle_client("../../oracle_local_client", config_dir= "../../oracle_local_client/network/admin")

connectDsn = cx_Oracle.makedsn('db.svr.net', 'portNumberHere',service_name="TEST_READWRITE")
#replace all prams above

pool = cx_Oracle.SessionPool(externalauth=True, homogeneous=False, dsn = connectDsn)
connection = pool.acquire(user="[PROXY_CLIENT_NAME]")

请注意使用'['括号来表示用户是proxyClient。 我正在使用Kerberos身份验证,我的SQLNET.ora文件包含以下属性。
NAMES.DIRECTORY_PATH=(TNSNAMES,HOSTNAME,EZCONNECT)
SQLNET.AUTHENTICATION_SERVICES = (BEQ,KERBEROS5PRE,KERBEROS5)
SQLNET.AUTHENTICATION_KERBEROS5_SERVICE=oracle
SQLNET.KERBEROS5_CC_NAME=OSMSFT:
SQLNET.KERBEROS5_CONF_MIT=TRUE
SQLNET.KERBEROS5_CONF=I:\projects\poc\resources\krb5.conf # krb5 config file complete path.

如需更多信息,请参考此文章中嵌入的视频。


0

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


0

我曾经一度认为我无法使用魔法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@'

-1

我也遇到了这个问题。 解决方案是:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接