我们通常不会用 Python 来直接调用 sqlplus.exe 这个命令行工具,虽然技术上可行(例如通过 subprocess 模块),但这是一种笨拙且不推荐的方法,因为它会启动一个新的、重量级的进程,难以处理复杂的交互,并且难以获取结构化的数据。

正确的、现代且推荐的方法是使用 Python 的数据库 API,特别是 cx_Oracle 库。 cx_Oracle 是一个官方支持的 Python 扩展模块,它允许 Python 程序无缝地访问 Oracle 数据库,其底层原理与 SQL*Plus 连接数据库的方式完全一致,都是通过 Oracle 的客户端库(如 Instant Client)。
这篇“Python SQLPlus 博客”的核心内容,实际上是 “使用 Python (cx_Oracle) 连接并操作 Oracle 数据库”。
博客文章:Python 与 Oracle 数据库的优雅邂逅:告别 SQL*Plus,拥抱自动化
作为一名开发者或数据分析师,你是否曾有过这样的烦恼:
- 每天都需要手动登录 SQL*Plus,执行固定的 SQL 查询,并将结果复制粘贴到 Excel 或报告中。
- 需要根据某些业务逻辑,动态生成并执行一系列 SQL 语句,手动操作效率低下且容易出错。
- 想将数据库操作集成到你的 Python 自动化流程(如 ETL、监控脚本)中,但 SQL*Plus 显得力不从心。
好消息是,Python 可以完美地解决这些问题,我们将告别传统的 SQL*Plus 命令行工具,学习如何使用 Python 强大的 cx_Oracle 库,与 Oracle 数据库进行优雅、高效的交互,开启数据库自动化的新篇章。

第一步:准备工作——安装与配置
在开始编码之前,我们需要确保环境已经准备就绪。
安装 Oracle 客户端
Python 的 cx_Oracle 库需要 Oracle 客户端库来与数据库通信,最简单的方式是使用 Oracle Instant Client。
- 下载:访问 Oracle Instant Client 官方下载页面。
- 选择版本:根据你的操作系统(Windows, Linux, macOS)和 Oracle 数据库版本选择合适的 Instant Client 包。
basic或basic-light包就足够了。 - 配置:
- Windows:解压下载的 zip 文件到一个固定目录(如
C:\oracle\instantclient_19_10),将该目录添加到系统的PATH环境变量中。 - Linux/macOS:解压到某个目录(如
/opt/oracle/instantclient_19_10),并确保该目录在系统的LD_LIBRARY_PATH(Linux) 或DYLD_LIBRARY_PATH(macOS) 环境变量中。
- Windows:解压下载的 zip 文件到一个固定目录(如
安装 Python 的 cx_Oracle 库

打开你的终端或命令提示符,使用 pip 进行安装:
pip install cx_Oracle
环境已经配置好了,让我们开始编写 Python 代码!
第二步:建立数据库连接
所有操作的第一步都是连接到数据库。cx_Oracle 提供了非常简洁的 API。
import cx_Oracle
# --- 配置信息 ---
# 建议从环境变量或配置文件中读取,而不是硬编码
db_user = "your_username"
db_password = "your_password"
db_dsn = "hostname:port/service_name" # "localhost:1521/XE"
try:
# 1. 创建连接
# 注意:如果你的 Instant Client 不在系统 PATH 中,需要指定其路径
# cx_Oracle.init_oracle_client(lib_dir="C:/oracle/instantclient_19_10")
connection = cx_Oracle.connect(user=db_user, password=db_password, dsn=db_dsn)
# 2. 创建游标
# 游标用于执行 SQL 语句并获取结果
cursor = connection.cursor()
print("成功连接到 Oracle 数据库!")
# ... 在这里执行你的数据库操作 ...
except cx_Oracle.DatabaseError as e:
error, = e.args
print(f"数据库错误代码: {error.code}")
print(f"数据库错误消息: {error.message}")
finally:
# 3. 关闭游标和连接
if 'cursor' in locals() and cursor:
cursor.close()
if 'connection' in locals() and connection:
connection.close()
print("数据库连接已关闭。")
代码解释:
cx_Oracle.connect(): 使用用户名、密码和数据源名称 建立连接。connection.cursor(): 创建一个游标对象,它是执行 SQL 的主力。try...except...finally: 这是处理数据库连接的最佳实践。try块执行操作,except捕获数据库错误,finally确保在任何情况下(无论成功或失败)都会关闭游标和连接,释放资源。
第三步:执行查询与获取数据
连接建立后,我们就可以执行 SQL 查询并处理结果了。
示例1:查询并打印结果
import cx_Oracle
# (使用上面的连接代码...)
try:
# --- 执行查询 ---
sql_query = "SELECT employee_id, first_name, last_name, salary FROM employees WHERE department_id = 10"
cursor.execute(sql_query)
# --- 获取结果 ---
# cursor.fetchone(): 获取下一行结果,返回一个元组,当没有更多数据时返回 None。
# cursor.fetchall(): 获取所有剩余的行,返回一个列表,其中每个元素是一个元组。
# cursor.fetchmany(size): 获取指定数量的行。
print("\n--- 部门ID为10的员工信息 ---")
# 使用 fetchone 循环处理,适合处理大量数据,节省内存
while True:
row = cursor.fetchone()
if not row:
break
print(f"员工ID: {row[0]}, 姓名: {row[1]} {row[2]}, 薪资: {row[3]}")
# 或者使用 fetchall
# rows = cursor.fetchall()
# for row in rows:
# print(f"员工ID: {row[0]}, 姓名: {row[1]} {row[2]}, 薪资: {row[3]}")
except cx_Oracle.DatabaseError as e:
# 错误处理...
pass
finally:
# 关闭连接...
pass
示例2:将查询结果转换为列表的字典(更 Pythonic 的方式)
直接使用元组访问列 (row[0]) 可读性不强,我们可以通过 cursor.description 获取列名,并将结果处理成字典列表,这在处理复杂数据时非常有用。
import cx_Oracle
# (使用上面的连接代码...)
try:
sql_query = "SELECT employee_id, first_name, last_name, salary FROM employees WHERE ROWNUM <= 5"
cursor.execute(sql_query)
# 获取列名
columns = [desc[0] for desc in cursor.description]
# 将每一行数据转换为字典
employees = []
for row in cursor:
employees.append(dict(zip(columns, row)))
print("\n--- 员工信息(字典格式)---")
for emp in employees:
print(emp)
except cx_Oracle.DatabaseError as e:
# 错误处理...
pass
finally:
# 关闭连接...
pass
第四步:执行 DML 语句(增删改)
对于 INSERT, UPDATE, DELETE 等数据操作语句,我们需要使用参数化查询来防止 SQL 注入,并确保数据安全。
示例:插入数据
import cx_Oracle
# (使用上面的连接代码...)
try:
# 注意:必须在连接上设置自动提交为 False,以便在出错时回滚
connection.autocommit = False
sql_insert = "INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, job_id) VALUES (:1, :2, :3, :4, SYSDATE, 'IT_PROG')"
new_employee = (999, 'Python', 'Tester', 'python.tester@example.com')
cursor.execute(sql_insert, new_employee)
# 提交事务
connection.commit()
print(f"成功插入 {cursor.rowcount} 行数据。")
except cx_Oracle.DatabaseError as e:
# 发生错误时回滚事务
connection.rollback()
print("发生错误,事务已回滚。")
# 错误处理...
pass
finally:
# 关闭连接...
pass
代码解释:
connection.autocommit = False: Oracle 默认不自动提交,这给了我们手动控制事务的机会。cursor.execute(sql, params): 使用1,2等作为占位符,然后将参数作为元组或列表传递给execute方法。cx_Oracle会安全地处理这些参数,防止 SQL 注入。connection.commit(): 提交事务,使更改永久生效。connection.rollback(): 回滚事务,撤销所有未提交的更改。
第五步:调用存储过程
Python 调用 Oracle 存储过程同样非常方便。
示例:调用一个带输入输出参数的存储过程
假设我们有一个存储过程 GET_EMP_SALARY,接收员工 ID,返回其薪资。
import cx_Oracle
# (使用上面的连接代码...)
try:
sql_proc = "{call GET_EMP_SALARY(:emp_id, :sal_out)}"
emp_id_to_find = 101
salary_var = cursor.var(cx_Oracle.NUMBER) # 定义一个变量来接收输出参数
cursor.callproc('GET_EMP_SALARY', [emp_id_to_find, salary_var])
# 获取输出参数的值
# 注意:输出参数的值在调用后存储在变量中
actual_salary = salary_var.getvalue()
print(f"\n员工ID {emp_id_to_find} 的薪资是: {actual_salary}")
except cx_Oracle.DatabaseError as e:
# 错误处理...
pass
finally:
# 关闭连接...
pass
总结与最佳实践
通过以上步骤,你已经掌握了使用 Python 操作 Oracle 数据库的核心技能,让我们总结一下关键点和最佳实践:
- 首选
cx_Oracle:不要尝试用subprocess调用sqlplus,cx_Oracle是更专业、更高效的选择。 - 环境配置是关键:确保 Oracle Instant Client 已正确安装并配置到系统路径中。
- 资源管理:始终使用
try...finally块来确保cursor和connection被正确关闭。 - 事务控制:对于 DML 操作,明确设置
autocommit = False,并在适当的时候调用commit()或rollback()。 - 防止 SQL 注入:永远不要用字符串拼接的方式构建 SQL 语句,始终使用参数化查询 (
cursor.execute(sql, params))。 - 错误处理:使用
try...except cx_Oracle.DatabaseError来捕获和处理数据库相关的错误。 - 代码结构化:将数据库连接信息(用户名、密码、DSN)存储在配置文件或环境变量中,而不是硬编码在脚本里。
你可以利用 Python 的强大功能,构建复杂的数据库自动化脚本,将重复性的工作交给机器,让自己专注于更有创造性的任务,Python 与 Oracle 的结合,将为你的工作效率带来质的飞跃!
