You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle APEX动态动作报ORA-20987 主键实时校验问题咨询

报错触发原因

这个错误是Oracle APEX的**会话状态保护(Session State Protection, SSP)**安全机制触发的:

  • APEX默认会给所有页面项开启会话状态保护,防止用户通过篡改URL、伪造AJAX请求的方式恶意修改受保护的项值。当项的保护级别为需要会话级校验和的档位时,所有修改、提交该项到会话状态的请求,必须携带和当前会话、项值匹配的加密校验和才会被放行。
  • 你自定义的动态动作在执行PL/SQL时,配置了提交P6_COUNTRY_ID到会话状态,但请求没有携带对应的合法校验和,因此被APEX判定为非法请求,直接抛出ORA-20987错误。

注意:不建议通过关闭页面项的会话状态保护来绕过这个报错,会引入参数篡改的安全风险。

现有方案合理性评估

你的实现思路方向是对的,但存在几个明显问题:

  • 额外创建隐藏项存储校验结果,增加了不必要的会话状态存储开销,流程冗余。
  • PL/SQL块使用WHEN OTHERS捕获所有异常的写法不严谨:除了主键不存在触发的NO_DATA_FOUND异常外,表权限缺失、字段名写错等其他无关异常也会被判定为「主键不存在」,会掩盖真实运行错误,出问题时连排查方向都找不到,逻辑漏洞很明显。
  • 没有适配编辑表单场景:如果页面是用来编辑已有的国家记录,输入当前记录本身的COUNTRY_ID也会被判定为重复,不符合业务逻辑。
  • 自定义动态动作的AJAX请求没有自动处理会话状态校验和,容易触发安全拦截报错。
更简便规范的实现方式

推荐直接用APEX原生的校验能力实现,不需要自定义动态动作、隐藏项,完全不会触发上述安全报错,实现步骤如下:

  1. 先清理之前创建的冗余配置:删除隐藏项P6_C_ID_CHECK、自定义的change触发动态动作全套配置。
  2. 在页面渲染树的「处理」-「校验」节点下新建校验:
    • 校验类型选择:不存在行的SQL查询(No Rows Returned)
    • 校验SQL语句写为:
    SELECT 1 
    FROM COUNTRY 
    WHERE COUNTRY_ID = :P6_COUNTRY_ID
    -- 编辑场景下追加以下条件,排除当前正在编辑的记录本身,避免误判
    -- 如果你的表单是基于ROWID定位记录,就用:P6_ROWID判断,如果是主键自身定位,调整为对应逻辑
    AND (:P6_ROWID IS NULL OR ROWID <> :P6_ROWID)
    
    • 关联校验的项选择P6_COUNTRY_ID,错误提示信息填写「输入的国家ID已存在,请重新输入」。
  3. 选中页面项P6_COUNTRY_ID,在属性面板的「高级」分组下,将**值改变时验证(Validate when Value Changes)**设置为「是」。

配置完成后,用户输入完P6_COUNTRY_ID失焦时,APEX会自动发起带合法校验和的AJAX请求执行校验,校验不通过时会直接在输入项下方显示错误提示,不需要手写任何提示逻辑、会话状态处理代码,是APEX官方推荐的标准实现方式,不用自己处理AJAX、校验和、提示位置这些杂事,兼容性和安全性都比自定义动态动作靠谱,维护起来也简单。

如果确实需要保留自定义动态动作的实现逻辑,不要关闭项的会话状态保护,只需要在执行PL/SQL的动作属性中,找到「会话状态」分组下的**发送校验和(Send Checksum)**选项开启即可,同时需要把PL/SQL里的WHEN OTHERS改为显式捕获NO_DATA_FOUND异常,补全编辑场景的自身记录排除逻辑。


内容的提问来源于stack exchange,提问作者dendiie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:12:17