使用SQLAlchemy向Oracle插入DataFrame时报DPI-1010未连接错误如何解决?
问题根因分析
你遇到的报错核心触发链路为:
- 首先抛出
ORA-3135错误:表示数据库连接在插入操作过程中被远端(Oracle实例/防火墙/网络设备)主动断开 - 后续的
DPI-1010: not connected是衍生错误:因为底层连接已经失效,SQLAlchemy尝试关闭游标时发现连接已经不存在
修复方案
- 优化SQLAlchemy引擎配置,增加连接存活检测、自动回收逻辑,避免无效连接被复用
新增pool_pre_ping(自动检测连接有效性)、pool_recycle(连接超时自动回收)参数,同时指定Oracle字符集避免乱码 - 使用上下文管理器管理连接生命周期,确保连接不会提前被释放,插入完成后主动提交事务
- 调整
chunksize参数:单次批量插入10000行容易触发网络传输超时,建议调整为1000~3000 - 修复字符串类型推导逻辑:如果对应字段全为空,
str.len().max()会返回NaN,会导致VARCHAR长度设置错误引发异常 - (cx_Oracle 8+版本必填)显式初始化Oracle Thick客户端,避免驱动兼容性导致的连接不稳定
完整修改后代码
import pandas as pd from sqlalchemy.engine import create_engine from sqlalchemy import types import cx_Oracle # cx_Oracle 8+ 必须加,替换为你本地的Oracle Instant Client路径,32/64位要和Python版本一致 # cx_Oracle.init_oracle_client(lib_dir="C:\\instantclient_19_18") DIALECT = 'oracle' SQL_DRIVER = 'cx_oracle' USERNAME = 'NCSWEB' # 替换为实际用户名 PASSWORD = '########' # 替换为实际密码 HOST = '192.168.213.151' # 替换为实际数据库地址 PORT = 1515 # 替换为实际端口 SERVICE = 'devnc12c' # 替换为实际服务名 ENGINE_PATH_WIN_AUTH = f"{DIALECT}+{SQL_DRIVER}://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/?service_name={SERVICE}" # 新增连接池配置 engine = create_engine( ENGINE_PATH_WIN_AUTH, pool_pre_ping=True, # 每次使用连接前检测是否存活 pool_recycle=300, # 连接空闲超过300秒自动回收 pool_size=10, connect_args={ "encoding": "UTF-8", "nencoding": "UTF-8" } ) # 先测试基础连接是否正常,排查账号/网络/权限问题 try: with engine.connect() as conn: res = conn.execute("SELECT 1 FROM DUAL") print("数据库连接正常,测试查询结果:", res.fetchone()) except Exception as e: print("基础连接失败,请检查账号/网络/服务名配置:", e) exit() # 读取CSV数据 fileName='C:\\Users\\ncdex1124\\Desktop\\New folder\\file4.csv' df = pd.read_csv(fileName) print(f"读取数据完成,共{len(df)}行") # 修复dtype推导逻辑,空字段默认设置长度为255 dtyp = {} for col in df.columns[df.dtypes == 'object']: max_len = df[col].str.len().max() # 处理空值、非数字情况 if pd.isna(max_len) or max_len <= 0: max_len = 255 dtyp[col] = types.VARCHAR(int(max_len)) try: # 用上下文管理器管理连接,插入完成后提交事务 with engine.connect() as conn: df.to_sql( name='FUT_CLIENT_LIST_COPY', # 表名如果指定schema的话用schema参数,不要写在name里 schema='UCIDBA', # 单独指定schema更规范 con=conn, if_exists='append', index=False, chunksize=2000, # 调小批量插入大小 dtype=dtyp ) conn.commit() # 显式提交事务,Oracle默认不自动提交 print("数据插入成功") except Exception as e: print("插入失败,错误信息:", e)
额外排查点
如果修改后还是连接失败,先排查基础网络问题:
- 用
telnet 192.168.213.151 1515检测端口是否通,不通的话需要找运维开通防火墙策略 - 用Oracle官方客户端sqlplus/PL/SQL Developer尝试连接目标库,确认账号密码、服务名配置正确
- 检查本地安装的Oracle Instant Client版本是否和服务端Oracle大版本兼容,优先使用11g/12c/19c版本的客户端
内容的提问来源于stack exchange,提问作者Alok Sharma
相关产品推荐
相关产品推荐

