无法从Wrapper过程异步调用Main过程,主过程未执行请求协助
问题描述
我希望从WRAPPER_MAIN_PROC过程异步调用MAIN_PROC过程。目前Wrapper过程的DBMS_OUTPUT.PUT_LINE可以正常输出,但Main过程的输出无显示,疑似Main过程未被成功调用。请协助解决该问题。
相关代码
表脚本
CREATE TABLE ASYNC_SAMPLE_TAB ( attribute1 varchar2(50), attribute2 varchar2(50) );
包规范
CREATE OR REPLACE PACKAGE XX_ASYNC_DEMO_PKG IS PROCEDURE MAIN_PROC( attribute1 IN VARCHAR2, attribute2 IN VARCHAR2 ); PROCEDURE WRAPPER_MAIN_PROC( attribute1 IN VARCHAR2, attribute2 IN VARCHAR2 ); END XX_ASYNC_DEMO_PKG;
包体
CREATE OR REPLACE PACKAGE BODY XX_ASYNC_DEMO_PKG IS PROCEDURE WRAPPER_MAIN_PROC( attribute1 IN VARCHAR2, attribute2 IN VARCHAR2 ) AS BEGIN DBMS_OUTPUT.PUT_LINE('-- START OF WRAPPER PROC---' || SYSTIMESTAMP); dbms_scheduler.create_job( job_name => 'ASYNC_MAIN_PROC' || '_' || attribute1, job_type => 'PLSQL_BLOCK', job_action => 'BEGIN MAIN_PROC(''' || attribute1 || ''', ''' || attribute2 || '''); END;', start_date => systimestamp , auto_drop => true, enabled => true ); DBMS_OUTPUT.PUT_LINE('-- END OF WRAPPER PROC---' || SYSTIMESTAMP); END; PROCEDURE MAIN_PROC( attribute1 IN VARCHAR2, attribute2 IN VARCHAR2 ) AS sql_stmt VARCHAR2(200); BEGIN DBMS_OUTPUT.PUT_LINE('-- START OF MAIN PROC---' || SYSTIMESTAMP); DBMS_SESSION.sleep(10); sql_stmt := 'INSERT INTO ASYNC_SAMPLE_TAB VALUES (:1, :2)'; EXECUTE IMMEDIATE sql_stmt USING attribute1, attribute2; DBMS_OUTPUT.PUT_LINE('-- END OF MAIN PROC---' || SYSTIMESTAMP); END; END XX_ASYNC_DEMO_PKG;
测试命令
exec XX_ASYNC_DEMO_PKG.WRAPPER_MAIN_PROC('Test101_1', 'Test101_2');
问题分析与解决方法
核心问题拆解
- DBMS_OUTPUT的局限性:
DBMS_OUTPUT的输出仅在当前会话可见,而DBMS_SCHEDULER创建的Job是在独立会话中执行的,所以主过程的输出不会显示在调用Wrapper的会话里,这不是主过程没执行,是输出无法跨会话传递。 - Job调用语法错误:Job的PL/SQL块里直接写
MAIN_PROC,但该过程属于XX_ASYNC_DEMO_PKG,未指定包名会导致Job执行时抛出“标识符无效”错误,实际主过程根本没跑起来。 - 事务未提交:主过程中的INSERT操作没有显式提交,Job执行结束后事务会自动回滚,导致数据没写入表,进一步加深“主过程未执行”的误解。
修复步骤
1. 修正Job中主过程的调用路径
在Job的PL/SQL块里必须指定完整的包名:
job_action => 'BEGIN XX_ASYNC_DEMO_PKG.MAIN_PROC(''' || attribute1 || ''', ''' || attribute2 || '''); END;'
2. 给主过程添加事务提交
确保INSERT的数据能持久化:
PROCEDURE MAIN_PROC( attribute1 IN VARCHAR2, attribute2 IN VARCHAR2 ) AS sql_stmt VARCHAR2(200); BEGIN DBMS_OUTPUT.PUT_LINE('-- START OF MAIN PROC---' || SYSTIMESTAMP); DBMS_SESSION.sleep(10); sql_stmt := 'INSERT INTO ASYNC_SAMPLE_TAB VALUES (:1, :2)'; EXECUTE IMMEDIATE sql_stmt USING attribute1, attribute2; COMMIT; -- 添加提交语句 DBMS_OUTPUT.PUT_LINE('-- END OF MAIN PROC---' || SYSTIMESTAMP); END;
3. 验证Job执行状态
查询USER_SCHEDULER_JOB_RUN_DETAILS确认Job是否成功执行:
SELECT job_name, status, error#, run_date FROM USER_SCHEDULER_JOB_RUN_DETAILS WHERE job_name LIKE 'ASYNC_MAIN_PROC%';
4. 替换DBMS_OUTPUT为日志表(可选)
如果需要查看主过程的执行日志,建议用日志表替代DBMS_OUTPUT,因为跨会话无法获取其输出:
首先创建日志表:
CREATE TABLE ASYNC_PROC_LOG ( log_time TIMESTAMP, proc_name VARCHAR2(50), log_msg VARCHAR2(200) );
然后修改主过程写入日志:
PROCEDURE MAIN_PROC( attribute1 IN VARCHAR2, attribute2 IN VARCHAR2 ) AS sql_stmt VARCHAR2(200); BEGIN INSERT INTO ASYNC_PROC_LOG VALUES(SYSTIMESTAMP, 'MAIN_PROC', '-- START OF MAIN PROC---'); DBMS_SESSION.sleep(10); sql_stmt := 'INSERT INTO ASYNC_SAMPLE_TAB VALUES (:1, :2)'; EXECUTE IMMEDIATE sql_stmt USING attribute1, attribute2; COMMIT; INSERT INTO ASYNC_PROC_LOG VALUES(SYSTIMESTAMP, 'MAIN_PROC', '-- END OF MAIN PROC---'); COMMIT; END;
验证方法
执行测试命令后,等待10秒以上,查询ASYNC_SAMPLE_TAB是否有新增数据,或查询ASYNC_PROC_LOG查看日志,同时通过USER_SCHEDULER_JOB_RUN_DETAILS确认Job执行状态。
内容的提问来源于stack exchange,提问作者mu shaikh
相关产品推荐
相关产品推荐

