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

Oracle Apex中PL/SQL包全局变量意外重置问题排查

问题原因

PL/SQL包的全局变量是数据库会话级的,但APEX的Ajax请求依赖数据库连接池,每次请求可能分配到不同的数据库会话。你的foo函数通过apex.server.process触发时,若当前请求用的是新的数据库会话,包变量g_current_var和g_expire_date就会被重置为null,导致每次都要调用REST API。

解决方案(无需数据库表)

以下几种方案均基于APEX应用会话级存储,能在APEX会话内保留值至过期:

1. 使用APEX应用项(Application Item)

创建两个应用项:P_RANDOM_NUM(存储随机数)和P_EXPIRE_DATE(存储过期时间字符串),修改MAIN_PKG.foo函数逻辑:

FUNCTION foo RETURN VARCHAR2 IS
    l_random_num VARCHAR2(100);
    l_expire_date DATE;
    l_response CLOB;
BEGIN
    -- 检查应用项中的值是否有效
    IF :P_RANDOM_NUM IS NULL OR SYSDATE > TO_DATE(:P_EXPIRE_DATE, 'YYYY-MM-DD HH24:MI:SS') THEN
        -- 调用REST API获取新值
        apex_web_service.g_request_headers(1).name := 'Content-Type';
        apex_web_service.g_request_headers(1).value := 'application/json';
        l_response := apex_web_service.make_rest_request(
            p_url => '你的API地址',
            p_http_method => 'POST',
            p_body => '{}' -- 按需调整请求体
        );
        
        -- 解析API响应(示例假设返回JSON格式)
        l_random_num := json_value(l_response, '$.random_num');
        l_expire_date := TO_DATE(json_value(l_response, '$.expire_at'), 'YYYY-MM-DD HH24:MI:SS');
        
        -- 更新应用项的会话状态
        apex_util.set_session_state('P_RANDOM_NUM', l_random_num);
        apex_util.set_session_state('P_EXPIRE_DATE', TO_CHAR(l_expire_date, 'YYYY-MM-DD HH24:MI:SS'));
    END IF;
    
    RETURN :P_RANDOM_NUM;
END foo;

应用项是绑定到APEX应用会话的,无论请求分配到哪个数据库会话,都能读取到同一批值。

2. 使用APEX缓存(APEX_CACHE)

APEX缓存支持键值对存储,并可设置过期时间,适合你的场景:

FUNCTION foo RETURN VARCHAR2 IS
    l_random_num VARCHAR2(100);
    l_expire_date DATE;
    l_response CLOB;
BEGIN
    -- 从缓存读取值
    l_random_num := apex_cache.get_string(
        p_cache_name => 'MAIN_PKG_CACHE',
        p_key => 'CURRENT_VAR'
    );
    l_expire_date := apex_cache.get_date(
        p_cache_name => 'MAIN_PKG_CACHE',
        p_key => 'EXPIRE_DATE'
    );
    
    -- 检查缓存是否有效
    IF l_random_num IS NULL OR SYSDATE > l_expire_date THEN
        -- 调用REST API获取新值
        apex_web_service.g_request_headers(1).name := 'Content-Type';
        apex_web_service.g_request_headers(1).value := 'application/json';
        l_response := apex_web_service.make_rest_request(
            p_url => '你的API地址',
            p_http_method => 'POST',
            p_body => '{}'
        );
        
        -- 解析响应
        l_random_num := json_value(l_response, '$.random_num');
        l_expire_date := TO_DATE(json_value(l_response, '$.expire_at'), 'YYYY-MM-DD HH24:MI:SS');
        
        -- 将值存入缓存,设置与API返回一致的过期时间
        apex_cache.put_string(
            p_cache_name => 'MAIN_PKG_CACHE',
            p_key => 'CURRENT_VAR',
            p_value => l_random_num,
            p_expire_on => l_expire_date
        );
        apex_cache.put_date(
            p_cache_name => 'MAIN_PKG_CACHE',
            p_key => 'EXPIRE_DATE',
            p_value => l_expire_date,
            p_expire_on => l_expire_date
        );
    END IF;
    
    RETURN l_random_num;
END foo;

APEX缓存默认是应用会话级的(也可设置为全局),能自动在过期时间后清理缓存值。

3. 前端会话存储(Session Storage)

如果随机数不涉及敏感数据,可在前端存储值,减少后端请求:

function fetchRandomNum() {
    const storedNum = sessionStorage.getItem('randomNum');
    const storedExpire = sessionStorage.getItem('expireDate');
    const now = new Date();
    
    // 检查前端缓存是否有效
    if (storedNum && storedExpire && new Date(storedExpire) > now) {
        return Promise.resolve(storedNum);
    }
    
    // 调用APEX Ajax流程
    return apex.server.process('Get_Main_data', {}, {
        success: function(data) {
            // 将值存入sessionStorage
            sessionStorage.setItem('randomNum', data.randomNum);
            sessionStorage.setItem('expireDate', data.expireDate);
            return data.randomNum;
        }
    });
}

// 打开模态框时调用
$('#modal').on('open', function() {
    fetchRandomNum().then(num => {
        // 使用随机数
        console.log(num);
    });
});

注意:sessionStorage仅在当前浏览器标签页的会话中有效,关闭标签页后会清除。

内容的提问来源于stack exchange,提问作者another apex user

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:23:23