我如何跟踪 cx_Oracle 是如何尝试连接到数据库的?
How can I trace how cx_Oracle is attempting to connect to the database?
我有三个 Python Anaconda 环境,其中安装了 cx_Oracle 和 Oracle 的 Instantclient。我正在使用 conda
提供虚拟环境,这似乎工作正常,并且我正在使用 Oracle Wallet 向系统提供实际凭据。请注意,这些环境不会也永远不会安装 SQL*Plus,因为它们只是为了通过更高的抽象(例如 Python 或 Java 与数据库通信).
我遇到的问题来自三种环境中的两种。执行以下 Python 脚本时,连接仅适用于三种环境之一。请注意,标识符在不同环境中有所不同,但大致相同。
import cx_Oracle
import os
os.environ['TNS_ADMIN'] = '/data/config/wallets/app'
conn = cx_Oracle.connect('/@ENV_CONNECTION')
当我在一个环境中执行此操作时,我得到了一个我期望的游标实例,并且一切正常。在另外两个上,我看到了这个:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-12162: TNS:net service name is incorrectly specified
我检查了五重服务名称和钱包本身。有一个 Java 应用程序也在使用这个钱包,如果钱包被认为是坏的,它将无法连接,所以我原则上排除了这种可能性。
唯一未知的是钱包本身是如何被引用的。
我如何反省 cx_Oracle 是如何引用我的 TNS_ADMIN 位置并拉入正确目录的?我觉得如果我能解决这个问题,我就可以解决剩下的问题。
我的环境:
- conda 4.4.11
- 即时客户端 12.2
- cx_Oracle 版本 6.3.1
检查 cx_Oracle 传递给较低层(例如 Oracle Net)的内容的最简单方法可能是扩展连接 class 并添加您自己的日志记录。基数 class 为 cx_Oracle.Connection
,见示例 https://github.com/oracle/python-cx_Oracle/blob/master/samples/Subclassing.py
您可以运行 strace 或类似工具查看正在打开哪些Oracle 配置文件,例如tnsnames.ora。
可以启用 Oracle 网络跟踪,请参阅 ADR Diagnostic Parameters in sqlnet.ora。对于简单的跟踪,我通常会创建一个文件“~/.sqlnet.ora”,其内容如下:
TRACE_LEVEL_CLIENT = USER
ADR_BASE=/tmp
然后 运行 应用程序,并通过创建的 /tmp/oradiag_*
目录向下挖掘到 *.trc
文件。
Christopher Jones 的回答让我得救了,但事实是问题远比这更微妙。
我最终在两台机器的主目录中创建了 sqlnet.ora
文件 - 一台可以工作,另一台没有。我注意到日志文件中存在显着差异。
"good" 框中有此条目:
2018-07-06 09:59:36.726 : nnftrne:Using tnsnames.ora address (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521)) (CONNECT_DATA = (SID = my_sid))) for name ENV_CONNECTION
"bad" 框中有此条目:
2018-07-06 10:02:12.879 : nnftrne:Using tnsnames.ora address (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521 for name ENV_CONNECTION
这最终转化为我遇到过的最愚蠢、最令人惊讶的空白限制之一。
请记住,正在使用的钱包(及其相应的 tnsnames.ora 文件)也在 Java 中使用。我的假设是 Python 和 Java 在从这个共享资源中读取时会表现相似,因为它们会在必要时忽略换行符和空格。
我显然错了。
"good" 框中的条目如下所示:
ENV_CONNECTION =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521))
(CONNECT_DATA =
(SID = my_sid)
)
)
"bad" 框中的条目如下所示:
ENV_CONNECTION =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521
))
(CONNECT_DATA =
(SID = my_sid)
)
)
差异非常细微,但对 Python 来说很明显:如果 tnsnames.ora 文件格式不正确,cx_Oracle 将 失败 解析它,而 Java 是 fine with this.
这本身就是一个错误,但修复格式后可以 Python 再次连接。
我有三个 Python Anaconda 环境,其中安装了 cx_Oracle 和 Oracle 的 Instantclient。我正在使用 conda
提供虚拟环境,这似乎工作正常,并且我正在使用 Oracle Wallet 向系统提供实际凭据。请注意,这些环境不会也永远不会安装 SQL*Plus,因为它们只是为了通过更高的抽象(例如 Python 或 Java 与数据库通信).
我遇到的问题来自三种环境中的两种。执行以下 Python 脚本时,连接仅适用于三种环境之一。请注意,标识符在不同环境中有所不同,但大致相同。
import cx_Oracle
import os
os.environ['TNS_ADMIN'] = '/data/config/wallets/app'
conn = cx_Oracle.connect('/@ENV_CONNECTION')
当我在一个环境中执行此操作时,我得到了一个我期望的游标实例,并且一切正常。在另外两个上,我看到了这个:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cx_Oracle.DatabaseError: ORA-12162: TNS:net service name is incorrectly specified
我检查了五重服务名称和钱包本身。有一个 Java 应用程序也在使用这个钱包,如果钱包被认为是坏的,它将无法连接,所以我原则上排除了这种可能性。
唯一未知的是钱包本身是如何被引用的。
我如何反省 cx_Oracle 是如何引用我的 TNS_ADMIN 位置并拉入正确目录的?我觉得如果我能解决这个问题,我就可以解决剩下的问题。
我的环境:
- conda 4.4.11
- 即时客户端 12.2
- cx_Oracle 版本 6.3.1
检查 cx_Oracle 传递给较低层(例如 Oracle Net)的内容的最简单方法可能是扩展连接 class 并添加您自己的日志记录。基数 class 为
cx_Oracle.Connection
,见示例 https://github.com/oracle/python-cx_Oracle/blob/master/samples/Subclassing.py您可以运行 strace 或类似工具查看正在打开哪些Oracle 配置文件,例如tnsnames.ora。
可以启用 Oracle 网络跟踪,请参阅 ADR Diagnostic Parameters in sqlnet.ora。对于简单的跟踪,我通常会创建一个文件“~/.sqlnet.ora”,其内容如下:
TRACE_LEVEL_CLIENT = USER ADR_BASE=/tmp
然后 运行 应用程序,并通过创建的/tmp/oradiag_*
目录向下挖掘到*.trc
文件。
Christopher Jones 的回答让我得救了,但事实是问题远比这更微妙。
我最终在两台机器的主目录中创建了 sqlnet.ora
文件 - 一台可以工作,另一台没有。我注意到日志文件中存在显着差异。
"good" 框中有此条目:
2018-07-06 09:59:36.726 : nnftrne:Using tnsnames.ora address (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521)) (CONNECT_DATA = (SID = my_sid))) for name ENV_CONNECTION
"bad" 框中有此条目:
2018-07-06 10:02:12.879 : nnftrne:Using tnsnames.ora address (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521 for name ENV_CONNECTION
这最终转化为我遇到过的最愚蠢、最令人惊讶的空白限制之一。
请记住,正在使用的钱包(及其相应的 tnsnames.ora 文件)也在 Java 中使用。我的假设是 Python 和 Java 在从这个共享资源中读取时会表现相似,因为它们会在必要时忽略换行符和空格。
我显然错了。
"good" 框中的条目如下所示:
ENV_CONNECTION =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521))
(CONNECT_DATA =
(SID = my_sid)
)
)
"bad" 框中的条目如下所示:
ENV_CONNECTION =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = my.oracle.db.host)(PORT = 1521
))
(CONNECT_DATA =
(SID = my_sid)
)
)
差异非常细微,但对 Python 来说很明显:如果 tnsnames.ora 文件格式不正确,cx_Oracle 将 失败 解析它,而 Java 是 fine with this.
这本身就是一个错误,但修复格式后可以 Python 再次连接。