SQLAlchemy带参数执行Oracle插入查询未生效问题
问题根因
代码生成的SQL手动执行正常、程序运行无报错但数据未插入的核心原因是SQLAlchemy默认开启事务且不自动提交,执行写操作后没有手动调用commit,连接关闭时事务会自动回滚,所有写操作都会被撤销。
除此之外代码还有几个潜在隐患:
- 用字符串格式化拼接SQL存在SQL注入风险,手动拼接日期字符串的写法高度依赖数据库端NLS_DATE_FORMAT、NLS_DATE_LANGUAGE参数配置,换环境很容易出现日期解析失败
- 没有异常捕获和回滚逻辑,执行出错时既无法定位问题,还可能导致数据库连接泄漏
- 手动拼接浮点型、整型参数容易出现格式转换错误
修复方案
- 执行完写操作后手动提交事务,异常场景下回滚事务
- 用SQLAlchemy的参数绑定语法替代字符串拼接,日期直接传原生datetime对象,由驱动完成类型适配,避免格式问题
- 增加finally块确保连接一定会被关闭
修复后的可运行代码:
from sqlalchemy.engine import create_engine from sqlalchemy import text import datetime DIALECT = 'oracle' SQL_DRIVER = 'cx_oracle' USERNAME = 'xxx' PASSWORD = 'xxx' HOST = 'pv-prod-orc-01.xxx.com' PORT = 1521 SERVICE = 'PVL01PD_APP.ec2.internal' ENGINE_PATH = f"{DIALECT}+{SQL_DRIVER}://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/?service_name={SERVICE}" engine = create_engine(ENGINE_PATH) conn = engine.connect() try: # 日期直接转为datetime对象,不需要手动格式化为字符串 target_date = datetime.datetime.strptime(Date, "%Y-%m-%d") # 用命名参数绑定写法,避免字符串拼接 stmt = text("call CORE_VALUATIONS.VALUATIONS.INSERTEQCLOSINGPRICE(:pkey, :closing_date, :price, NULL, NULL)") conn.execute(stmt, { "pkey": int(Pkey), "closing_date": target_date, "price": float(price) }) # 核心:提交事务,否则所有修改都会被回滚 conn.commit() print("价格数据插入成功") except Exception as e: conn.rollback() print(f"插入失败,错误详情:{str(e)}") finally: conn.close()
补充说明
- 如果不想手动管理事务,可以在创建引擎时开启自动提交:
engine = create_engine(ENGINE_PATH, isolation_level="AUTOCOMMIT"),但生产环境更推荐手动控制事务粒度,避免误写数据。 - 用PL/SQL Developer、Navicat等客户端手动执行SQL能直接生效,是因为这类工具默认开启了自动提交,和程序默认的事务行为不一致,这也是两边执行结果不同的核心原因。
- 不要手动把日期转为
'01Oct2024'这类字符串传入,如果Oracle实例的日期语言配置不是英文,会直接报日期格式不匹配错误,传原生datetime对象是兼容性最好的做法。
问题运行截图:
内容的提问来源于stack exchange,提问作者Rahul Vaidya
相关产品推荐
相关产品推荐

