Python使用oracledb连接Oracle数据库的代码示例与TNS配置

青禾
青禾
发布时间:2026-10-31| 8人浏览过
原创

本文详细介绍在Python中使用官方新一代驱动python-oracledb连接Oracle数据库的完整方法,涵盖Thin与Thick模式区别、tnsnames.ora配置文件编写、config_dir与TNS_ADMIN寻址路径指定、基础查询与高并发连接池代码示例及常见报错排查。

技术领域:Python / Oracle Database 驱动版本:python-oracledb ≥ 1.0 配置核心:tnsnames.ora / TNS_ADMIN
Python使用oracledb连接Oracle数据库的代码示例与TNS配置
架构总览:基于 python-oracledb 的 TNS 别名寻址与 Oracle 数据库连接流程
python-oracledb 是 Oracle 官方推出的新一代 Python 数据库驱动库,也是长期被广泛使用的 cx_Oracle 的官方正统继任者。与旧驱动最大的区别在于,python-oracledb 默认运行在纯 Python 实现的 Thin 模式下,无需在宿主机上下载或配置臃肿的 Oracle Instant Client 动态链接库即可直连数据库。在生产环境与企业多系统部署中,直接硬编码 IP、端口和服务名容易引发耦合过紧、迁移不便等问题;借助透明网络底座(Transparent Network Substrate,简称 TNS)以及 tnsnames.ora 别名配置文件,能将网络地址细节与代码完全解耦。本文将依次讲解驱动安装、双模式特性、TNS 配置语法、寻址路径指定、完整 Python 代码示例以及连接池与故障诊断。

一、认识 python-oracledb 及其连接模式

在编写连接代码之前,读者需要理解 python-oracledb 提供的两种不同运作模式:Thin 模式(轻量模式)与 Thick 模式(兼容模式)。明确两者的运行机理,有助于在架构设计和环境选型时做出正确的决策。

  • Thin 模式(纯 Python 默认模式):驱动内置了 Oracle Net 协议的纯 Python 解析与通信引擎。代码执行 import oracledb 后默认即为此模式。该模式完全不依赖 C 共享库(如 libclntsh.so、oci.dll),支持直连 Oracle Database 12.1 及更高版本,特别适合 Docker 容器化打包、轻量 Web 微服务和无编译环境的自动化脚本。
  • Thick 模式(C 库兼容模式):当在执行任何数据库连接动作前显式调用 oracledb.init_oracle_client() 时,驱动会切换至 Thick 模式。此模式基于 ODPI-C 桥接本地安装的 Oracle Instant Client 动态链接库。该模式主要用于向下兼容已处于维护末期的 Oracle Database 11.2,或者需要使用高级网络安全特性(如 Kerberos、RADIUS 认证、外部认证钱包等)的特殊场景。
Python使用oracledb连接Oracle数据库的代码示例与TNS配置
图 1:python-oracledb Thin 模式与 Thick 模式的协议分层与底层依赖对比

无论是 Thin 模式还是 Thick 模式,python-oracledb 均完整支持读取和解析标准 tnsnames.ora 文件。在绝大多数日常开发与企业应用中,推荐优先采用 Thin 模式,以获得免客户端安装的极大便利。

二、环境准备与 TNS 配置文件编写

通过 TNS 连接数据库,本质上是让 Python 驱动在建立网络连接前,根据传入的“网络服务别名(Net Service Name)”,去本地磁盘中找到 tnsnames.ora 文件并提取对应的目标 IP、端口和服务名称。本节演示环境安装及配置文件的编写规范。

1. 安装驱动包

使用 pip 命令安装官方最新版本的 oracledb。需要确认系统中的 Python 版本在 3.8 及以上:

BASH终端执行
pip install oracledb
终端输出示例
Successfully installed oracledb-2.4.0
版本演进提示
如果项目中此前使用了旧版 cx_Oracle,官方支持直接迁移。在代码顶部执行 import oracledb; oracledb.upgrade_mode(),即可保持原有 cx_Oracle 命名空间的代码无缝向下兼容。

2. 编写 tnsnames.ora 文件

选择一个固定的本地目录(例如 Linux/macOS 环境下的 /opt/oracle/network/admin,或 Windows 环境下的 C:\oracle etworkdmin,亦或是项目目录下的 ./config 文件夹),创建名为 tnsnames.ora 的纯文本文件。

在文件中添加如下配置内容。这里我们配置两个典型别名:一个是常用的单实例别名 ORCL_PROD,另一个是具备故障转移(Failover)与负载均衡(Load Balance)能力的高可用别名 ORCL_RAC:

TNSNAMES.ORA网络服务定义文件
# 单实例生产数据库配置
ORCL_PROD =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.100)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orclpdb1.localdomain)
    )
  )

# RAC 高可用集群配置(带故障转移)
ORCL_RAC =
  (DESCRIPTION =
    (LOAD_BALANCE = on)
    (FAILOVER = on)
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.101)(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.102)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = racdb.localdomain)
    )
  )

3. 配置语法关键项解析

  • ORCL_PROD:网络服务名别名,后续 Python 代码中的 dsn 参数将直接使用此名称。
  • PROTOCOL = TCP:通信协议,一般为常规 TCP;如启用了 SSL/TLS 加密则为 TCPS。
  • HOST / PORT:数据库监听器所在的主机名或 IP,以及监听端口(默认 1521)。
  • SERVICE_NAME:Oracle 推荐的服务名。注意区分 SERVICE_NAME 与旧式的 SID,连接可插拔数据库(PDB)时必须使用服务名。

4. 确定配置文件的寻址路径

Python 驱动必须知道去哪里寻找 tnsnames.ora。python-oracledb 提供了两种推荐的标准寻址手段:

  1. 在代码参数中显式指定 config_dir:在调用 oracledb.connect() 或创建连接池 create_pool() 时,传入参数 config_dir="/opt/oracle/network/admin"。这种方式对宿主环境没有侵入性,不同项目可以各自隔离配置。
  2. 设置操作系统环境变量 TNS_ADMIN:若不想在代码中写死目录,可在操作系统或部署脚本中设置环境变量,例如 export TNS_ADMIN=/opt/oracle/network/admin。驱动在没有显式传递 config_dir 时,会自动检索该环境变量所指目录。
Python使用oracledb连接Oracle数据库的代码示例与TNS配置
图 2:使用 python-oracledb 配置 TNS 别名并建立交互的标准实施五步法

三、Python 连接代码示例与实战应用

完成配置后,本节通过具体的 Python 脚本演示如何使用 TNS 别名完成基础数据查询、Thick 模式切换以及高并发连接池的管理。

1. 基础连接与游标查询(默认 Thin 模式)

推荐始终使用 Python 的 with 上下文管理器来管理 Connection 和 Cursor。当代码块执行完毕或遇到异常跳出时,系统会自动关闭游标并安全释放数据库会话连接,杜绝连接泄露。

PYTHONtest_thin_tns.py
import os
import oracledb

# 数据库账号密码建议通过环境变量注入,避免代码硬编码
DB_USER = os.getenv("DB_USER", "hr")
DB_PASS = os.getenv("DB_PASS", "hr_secure_password")
# TNS 别名与配置文件所在目录
TNS_ALIAS = "ORCL_PROD"
TNS_DIR = "/opt/oracle/network/admin"

def run_query():
    # 建立数据库连接:dsn 直接传入别名,config_dir 传入 tnsnames.ora 所在目录
    with oracledb.connect(
        user=DB_USER,
        password=DB_PASS,
        dsn=TNS_ALIAS,
        config_dir=TNS_DIR
    ) as connection:
        print(f"成功连接至数据库!Thin 模式状态: {connection.thin}")
        print(f"数据库服务端版本: {connection.version}")

        # 创建游标执行 SQL
        with connection.cursor() as cursor:
            sql = """
                SELECT banner 
                FROM v$version 
                WHERE ROWNUM = 1
            """
            cursor.execute(sql)
            row = cursor.fetchone()
            if row:
                print(f"数据库 Banner 信息: {row[0]}")

if __name__ == "__main__":
    run_query()
终端运行输出示例
成功连接至数据库!Thin 模式状态: True 数据库服务端版本: 19.3.0.0.0 数据库 Banner 信息: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

2. 厚客户端(Thick 模式)连接示例

当需要对接 Oracle 11g 等早期版本或使用本地 Wallet 证书时,需在程序启动前调用 init_oracle_client()。请注意:该方法在每个 Python 解释器进程的生命周期内只能被成功执行一次。

PYTHONtest_thick_tns.py
import oracledb

# 指定 Instant Client C 库目录与 TNS 配置文件目录
CLIENT_LIB_DIR = "/opt/oracle/instantclient_19_19"
TNS_CONFIG_DIR = "/opt/oracle/network/admin"

try:
    # 显式初始化 Thick 模式,同时绑定 config_dir
    oracledb.init_oracle_client(
        lib_dir=CLIENT_LIB_DIR,
        config_dir=TNS_CONFIG_DIR
    )
    print("成功初始化 Oracle Thick 模式客户端")
except Exception as e:
    print(f"Thick 模式初始化失败: {e}")

# 初始化完成后,连接调用无需重复传 config_dir
with oracledb.connect(
    user="hr",
    password="hr_secure_password",
    dsn="ORCL_PROD"
) as connection:
    print(f"当前 Thin 模式标识: {connection.thin}")  # 输出 False 即为 Thick 模式
    with connection.cursor() as cursor:
        cursor.execute("SELECT sys_context('USERENV', 'SESSION_USER') FROM dual")
        print("当前登录会话用户:", cursor.fetchone()[0])

3. 连接描述形式对比:TNS 别名 vs Easy Connect

在实际工程中,除了 TNS 别名,还可以使用 Easy Connect 字符串或直接书写完整的 Connect Descriptor。各方式对比如下:

连接形式 典型语法示例 核心优势 主要不足与适用场景
TNS 别名 (推荐) dsn="ORCL_PROD" 网络拓扑集中在配置文件中管理,支持复杂的 RAC 故障转移与负载均衡,代码与网络环境彻底解耦。 需在客户端维护 tnsnames.ora 文件,需指定 config_dir。适合生产环境与企业微服务。
Easy Connect dsn="192.168.1.100:1521/orclpdb1" 无需任何额外的配置文件,一行代码直接包含地址与端口,开箱即测。 无法直接配置负载均衡组或复杂连接参数,IP 变更需要改动代码或环境变量。适合临时调试与单元测试。
完整描述符 dsn="(DESCRIPTION=(ADDRESS=...))" 可直接在代码内编写完整的高级参数,无需物理文件。 连接串冗长易错,修改维护成本高。适合无法落盘配置文件的受限环境。

4. 生产高并发场景:基于 TNS 的连接池(Connection Pool)

对于 Web API(如 FastAPI、Flask、Django)或高频处理任务,频繁建立与断开 TCP 连接和 Oracle 会话会带来巨大的系统开销。使用 oracledb.create_pool() 构建连接池是企业生产的标准实践。

PYTHONpool_tns_service.py
import oracledb

# 初始化全局连接池
pool = oracledb.create_pool(
    user="hr",
    password="hr_secure_password",
    dsn="ORCL_PROD",
    config_dir="/opt/oracle/network/admin",
    min=2,             # 初始保活连接数
    max=10,            # 最大并发连接数
    increment=1,       # 扩容步长
    getmode=oracledb.POOL_GETMODE_WAIT,
    wait_timeout=5000  # 获取连接超时(毫秒)
)

def query_employee(emp_id: int):
    # 从连接池借出连接,使用完成后自动归还连接池
    with pool.acquire() as connection:
        with connection.cursor() as cursor:
            cursor.execute(
                "SELECT first_name, last_name, salary FROM employees WHERE employee_id = :id",
                id=emp_id
            )
            return cursor.fetchone()

# 模拟业务调用
if __name__ == "__main__":
    result = query_employee(100)
    print("员工查询结果:", result)
    # 服务停止时关闭连接池
    pool.close()

四、TNS 别名解析机制与通信链路深析

当执行 oracledb.connect(dsn="ORCL_PROD", config_dir="...") 时,底层的通信时序与状态流转如下图所示:

Python使用oracledb连接Oracle数据库的代码示例与TNS配置
图 3:TNS 别名匹配解析、网络 TCP 握手到服务进程分派的全链路数据流向

整个过程可划分为三个关键阶段:

  1. 本地寻址与语法解析:驱动定位到 config_dir 目录,读取 tnsnames.ora 文件并对文本进行语法树解析,定位到 ORCL_PROD 节,解析出 HOST、PORT 以及 SERVICE_NAME。
  2. TCP 网络握手与监听协商:驱动发起针对目标端口(如 1521)的 TCP 连接。握手成功后,发送 Oracle Net 协议的连接请求包(Connect Packet),携带所需请求的服务名称及版本元数据。
  3. 监听重定向与会话鉴权:Oracle 监听器接收到请求,核对该实例下服务名是否处于就绪(READY)状态。如果是专用连接模式,监听器创建或重定向到一个 Dedicated Server Process 专有进程,由该进程与 Python 客户端完成用户密码安全哈希握手,最终返回会话建立成功的响应。

五、常见报错原因与排查方案

在配置和使用 TNS 连接的过程中,读者最常遇到以下几类错误。掌握这些错误的核心成因能大幅提升故障定位效率。

Python使用oracledb连接Oracle数据库的代码示例与TNS配置
图 4:驱动选型决策树与高频网络/认证故障定位排查矩阵

1. ORA-12154 或 DPY-4001: 无法解析连接标识符 / 找不到配置文件

现象描述:执行连接时抛出 DPY-4001: cannot open file .../tnsnames.ora 或 ORA-12154: TNS:could not resolve the connect identifier specified。

排查步骤:

  • 确认 config_dir 传入的目录真实存在,且路径中不要包含文件名本身(只传目录路径,不要写成 /path/to/tnsnames.ora)。
  • 确认当前运行 Python 脚本的系统用户对该文件拥有读权限(Linux 下建议 chmod 644 tnsnames.ora)。
  • 打开 tnsnames.ora,检查左右括号是否严格匹配。如果括号嵌套存在缺失,解析器会直接跳过该别名。
  • 检查代码中 dsn="ORCL_PROD" 的别名拼写,包括大小写与是否有不可见多余空格。

2. ORA-12541: TNS:no listener(无监听器)

现象描述:网络链路已通,但报错没有监听器响应。

排查步骤:

  • 登录 Oracle 数据库服务器,执行 lsnrctl status 检查监听器是否已启动。
  • 在客户端机器上使用 nc -zv 192.168.1.100 1521 或 telnet 192.168.1.100 1521,验证中间是否存在防火墙或云安全组阻断了 TCP 1521 端口。

3. ORA-01017: invalid username/password; logon denied(用户名/密码错误)

现象描述:身份验证拒绝。

排查步骤:

  • Oracle 11g 及以上版本默认对密码大小写敏感,确认传入的字符串与数据库实际创建时完全一致。
  • 如果密码中包含特殊字符(如 @ 或双引号),在通过环境变量或终端传入时需防止被 Shell 转义破坏。

4. DPY-4000: Oracle Client library cannot be loaded

现象描述:提示无法加载 Oracle Client 动态链接库。

排查步骤:

  • 这是由于代码调用了 oracledb.init_oracle_client() 进入了 Thick 模式,但操作系统未安装 Oracle Instant Client,或 lib_dir 路径不正确。
  • 若连接的数据库在 12.1 及以上且无需特殊认证,直接删除 init_oracle_client() 这一行调用,保留默认的 Thin 模式即可完美运行。

六、技术要点总结与速查清单

最后,我们将使用 python-oracledb 结合 TNS 配置的核心知识点总结为一份开发快速检查清单:

  1. 模式定夺:绝大多数现代项目直接使用默认的 Thin 模式,享受免装 Instant Client 库的纯净体验;仅在对接老库或特殊加密时调用 init_oracle_client()。
  2. 别名维护:在 tnsnames.ora 中集中维护 ADDRESS 与 CONNECT_DATA,解耦 IP 端口变动。
  3. 路径指定:优先在代码连接处显式声明 config_dir 参数,或者统一配置 TNS_ADMIN 系统环境变量。
  4. 资源生命周期:单次事务与批处理严格配合 with oracledb.connect(...) 释放连接;长时间常驻服务与 Web 后端统一使用 oracledb.create_pool() 连接池复用连接。
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。