【问题标题】:cx_Oracle doesn't connect when using SID instead of service name on connection stringcx_Oracle 在连接字符串上使用 SID 而不是服务名称时不连接
【发布时间】: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,但不适用于服务名称)

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

【问题讨论】:

    标签: python oracle python-2.7 cx-oracle


    【解决方案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 谢谢,很高兴听到它有帮助:-)
              • 经过一个月的搜索,并使用了不同种类的目录和环境变量,这就是最终让我连接到服务器并开始拉数据的答案。很不错
              猜你喜欢
              • 2011-06-17
              • 1970-01-01
              • 2012-11-21
              • 2021-10-11
              • 1970-01-01
              • 2011-06-06
              相关资源
              最近更新 更多