在 Python 中使用 ODBC 连接到 Oracle

Connect to Oracle with ODBC in Python

我成功安装了 Oracle 12.2.01,运行 它的官方 Docker image 在 64 位 Linux 上:

docker run --name oracle12-se2 -p 1521:1521 -p 5500:5500 -e ORACLE_PWD=my_pwd oracle/database:12.2.0.1-se2

数据库似乎 运行 正确,我可以输入它的 SQL > 提示:

docker exec -ti oracle12-se2 sqlplus system@ORCLPDB1

并在那里发出命令。

但是尝试通过 Python 的 pyodbc 从另一台 Linux 机器连接失败。我使用的是官方 Oracle Instant Client + ODBC 驱动程序 19.3,但我迷失在所有首字母缩略词中:DBQ、SID、DSN、TSN、实例、SERVER_NAME、tnsnames.ora、端口……None 以下作品:

import pyodbc  # version 4.0.26
conn_params = [
    {'server': '175.201.160.29:1521', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"},
    {'server': '175.201.160.29:1521/ORCLCDB', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"},
    {'server': '175.201.160.29:1521/ORCLPDB1', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"},
    {'dbq': '175.201.160.29:1521', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"},
    {'dbq': '175.201.160.29:1521/ORCLCDB', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"},
    {'dbq': '175.201.160.29:1521/ORCLPDB1', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"},
]
for attempt in conn_params:
    try:
        conn = pyodbc.connect(**attempt)
        print('SUCCESS!')
    except Exception:
        print('failed with', attempt)

错误总是 Error: ('IM004', "[IM004] [unixODBC][Driver Manager]Driver's SQLAllocHandle on SQL_HANDLE_HENV failed (0) (SQLDriverConnect)")。如何调试?


编辑: 我取得了一些进展。我可以使用 cx-oracle 而不是 pyodbc:

成功连接到远程数据库
import cx_Oracle
connection = cx_Oracle.connect("system", "my_pwd", "175.201.160.29/ORCLPDB1")
# …connection cursors work as expected, all good

我想这证明数据库或连接本身没有问题。但是,我需要 pyodbc 才能工作,而不是 cx-oracle,所以我上面的问题仍然成立。

我仍然对所有 Oracle 术语一头雾水(您需要多少 BS 才能连接到数据库?),但以下似乎有效:

$ # on the machine with pyodbc
$ export ORACLE_HOME=/opt/oracle/instantclient_19_3
$ cat $ORACLE_HOME/network/admin/tnsnames.ora

LISTENER = (ADDRESS=(PROTOCOL=tcp)(HOST=175.201.160.29)(PORT=1521))

test=
 (DESCRIPTION=
   (ADDRESS=(PROTOCOL=tcp)(HOST=175.201.160.29)(PORT=1521))
   (CONNECT_DATA=(SERVICE_NAME=ORCLCDB)))

然后从Python:

>>> import pyodbc
>>> conn = pyodbc.connect(**{'DBQ': 'test', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"})
>>> list(conn.cursor().execute("""select * from global_name"""))
[('ORCLCDB', )]

不确定为什么 pyodbc 需要该文件而 cx-oracle 不需要。

不需要创建额外 tnsnames.ora 文件的解决方案:

import pyodbc

conn = pyodbc.connect(**{'DBQ': '175.201.160.29/ORCLPDB1', 'uid': 'system', 'pwd': 'my_pwd', 'driver': "Oracle 19 ODBC driver"})
print(list(conn.cursor().execute("""select * from global_name""")))

[('ORCLCDB', )]