Oracle APEX中DBMS_SCHEDULER遇浏览器刷新重复生成作业求助
问题分析与解决方案
核心问题
Apex仪表板中通过按钮触发的DBMS_SCHEDULER作业,近期出现浏览器/页面刷新时也会重复触发的情况,导致同一时间生成多个作业实例,仅需保留按钮点击触发的逻辑。
排查方向与解决步骤
1. 修正动态动作触发条件
检查触发作业的动态动作配置:
- 确保触发类型仅为按钮点击,不要勾选页面加载、刷新或其他无关触发事件;
- 确认动态动作仅绑定到目标按钮,未误绑定到页面全局事件。
2. 切换请求方式为POST
若按钮使用GET方式提交请求,浏览器刷新会重发上次请求导致重复执行作业:
- 修改按钮的
Action属性为Submit Page,并确保请求方法为POST; - 若使用AJAX动态动作执行PL/SQL,确认未手动将请求方式改为GET(Apex默认AJAX执行PL/SQL为POST)。
3. 优化PL/SQL代码,避免重复触发
当前代码的循环逻辑和无锁处理会导致重复请求时多次触发作业,调整如下:
- 使用
FOR UPDATE SKIP LOCKED防止并发请求选取同一记录; - 处理前更新记录状态为
IN_PROGRESS,避免后续请求重复处理; - 移除不必要的循环,改为单次处理逻辑(原循环会在单次请求中多次触发作业,刷新后会再次执行整个循环)。
修改后的PL/SQL示例:
BEGIN DECLARE v_current_group AUTOMATION_execution_plan.LOGICAL_GROUP_NAME%TYPE; BEGIN -- 加锁跳过已被处理的记录,防止并发重复选取 SELECT LOGICAL_GROUP_NAME INTO v_current_group FROM AUTOMATION_execution_plan WHERE seq_number = :SEQ_NUM AND status = 'WAITING' ORDER BY execution_group_seq, execution_method_seq FETCH NEXT 1 ROWS ONLY FOR UPDATE SKIP LOCKED; -- 更新状态为执行中,避免后续请求重复处理 UPDATE AUTOMATION_execution_plan SET status = 'IN_PROGRESS' WHERE LOGICAL_GROUP_NAME = v_current_group AND seq_number = :SEQ_NUM; COMMIT; -- 设置作业参数并执行 DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('PRD_APEX_OS_RUNNER_ARGS',1,'start -p UnityClone122 -t ACDEV -l SOLR_Post_Clone -k <keypass>' ); DBMS_SCHEDULER.RUN_JOB ('PRD_APEX_OS_RUNNER_ARGS' , false); EXCEPTION WHEN NO_DATA_FOUND THEN NULL; -- 无等待处理的记录时直接退出 WHEN OTHERS THEN -- 建议将错误日志写入专门的表,替代dbms_output方便排查 INSERT INTO AUTOMATION_ERROR_LOG (error_message, log_timestamp) VALUES (SQLERRM, SYSTIMESTAMP); COMMIT; END; END;
4. 限制作业并发执行
在触发作业前检查是否已有同名称作业在运行,避免重复启动:
DECLARE v_job_running NUMBER; BEGIN SELECT COUNT(*) INTO v_job_running FROM DBA_SCHEDULER_RUNNING_JOBS WHERE JOB_NAME = 'PRD_APEX_OS_RUNNER_ARGS' AND OWNER = 'XXARW_AUTOMATION'; IF v_job_running = 0 THEN DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE('PRD_APEX_OS_RUNNER_ARGS',1,'start -p UnityClone122 -t ACDEV -l SOLR_Post_Clone -k <keypass>' ); DBMS_SCHEDULER.RUN_JOB ('PRD_APEX_OS_RUNNER_ARGS' , false); END IF; END;
5. 添加页面防重复提交令牌
在Apex页面中创建隐藏项(如PXX_SUBMIT_TOKEN),每次按钮点击时生成唯一UUID:
- 在按钮的动态动作中,先生成令牌并写入隐藏项;
- 执行PL/SQL前验证令牌是否未被使用,使用后标记为已用(可存入临时表或会话变量);
- 刷新页面时令牌会重置,避免重复提交。
内容的提问来源于stack exchange,提问作者Niki
相关产品推荐
相关产品推荐

