Airflow BashOperator执行SQLPlus脚本报Error 45问题求助
问题:Airflow BashOperator执行SQL*Plus脚本时报Error 45(非本地文件系统不兼容)
命令行直接运行bash脚本可正常执行SQLPlus命令,但通过Airflow DAG的BashOperator调用时,触发SQLPlus初始化错误Error 45,提示信息:
使用了与SQL Plus不兼容的非本地文件系统
核心原因
Airflow的BashOperator默认工作目录通常是Airflow的dags目录,如果该目录挂载在NFS、S3挂载目录等非本地文件系统上,SQL*Plus初始化时需要读写本地临时文件,无法在非本地文件系统完成这类操作,就会抛出该错误。
解决方案
方案1:指定BashOperator工作目录为本地路径
在BashOperator中通过cwd参数指定本地临时目录,让SQL*Plus在本地文件系统环境下执行:
修改后的DAG代码示例:
from airflow import DAG from airflow.operators.bash import BashOperator from datetime import datetime import os default_args = { 'owner': 'airflow', 'start_date': datetime(2024, 1, 1), } with DAG('sqlplus_dag', default_args=default_args, schedule_interval='@daily') as dag: run_sql_script = BashOperator( task_id='run_sql_script', # 先创建临时目录再执行脚本 bash_command='mkdir -p /tmp/airflow_sqlplus_temp && /path/to/your/script.sh', # 指定本地工作目录 cwd='/tmp/airflow_sqlplus_temp' )
同时修改bash脚本,把SQL文件复制到本地临时目录后再执行:
#!/bin/bash # 把SQL脚本复制到本地临时目录 cp /path/to/your/sql_script.sql /tmp/airflow_sqlplus_temp/ # 执行SQL*Plus命令 sqlplus username/password@db @sql_script.sql # 清理临时文件 rm /tmp/airflow_sqlplus_temp/sql_script.sql
方案2:设置SQL*Plus临时目录环境变量
SQL*Plus会读取TMP或TEMP环境变量作为临时文件存储路径,直接在BashOperator中指定这两个变量为本地路径:
DAG代码示例:
run_sql_script = BashOperator( task_id='run_sql_script', bash_command='/path/to/your/script.sh', # 注入本地临时目录环境变量,保留原有系统环境变量 env={ 'TMP': '/tmp/airflow_sqlplus', 'TEMP': '/tmp/airflow_sqlplus', **os.environ } )
在bash脚本开头添加目录创建命令:
mkdir -p /tmp/airflow_sqlplus
更优任务编写方式:使用OracleOperator替代BashOperator
如果Airflow环境已安装apache-airflow-providers-oracle插件,建议直接用OracleOperator执行SQL,彻底避开SQL*Plus的文件系统依赖问题,同时更符合Airflow的任务编排规范:
示例代码:
from airflow import DAG from airflow.providers.oracle.operators.oracle import OracleOperator from datetime import datetime default_args = { 'owner': 'airflow', 'start_date': datetime(2024, 1, 1), } with DAG('oracle_sql_dag', default_args=default_args, schedule_interval='@daily') as dag: run_oracle_sql = OracleOperator( task_id='run_oracle_sql', oracle_conn_id='your_oracle_connection', # 提前在Airflow UI配置Oracle连接 sql='/path/to/your/sql_script.sql' # 也可以直接写SQL语句:sql="INSERT INTO your_table VALUES (1, 'test');" )
这种方式通过Python的cx_Oracle库直接连接Oracle执行SQL,无需依赖SQL*Plus,日志输出更清晰,任务状态监控也更方便。
内容的提问来源于stack exchange,提问作者Scott Luisi
相关产品推荐
相关产品推荐

