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

Oracle 19c下如何确保同一会话中PROC_BEGIN与PROC_END更新日志表的同一条记录

Oracle 19c下如何确保同一会话中PROC_BEGIN与PROC_END更新日志表的同一条记录

嘿,这个坑我之前做ETL日志系统的时候踩过!用日期+过程名来匹配更新确实会在多用户并发的时候出问题——毕竟同一时间可能有好几个用户跑同一个存储过程,数据库根本分不清哪条日志属于哪个会话,自然就会出现重复更新或者更新错记录的情况。下面给你几个在Oracle 19c里实测靠谱的解决方案:

方法一:利用Oracle会话唯一标识(最省事的方案)

Oracle每个会话都有一个全局唯一的SESSIONID,可以通过SYS_CONTEXT('USERENV','SESSIONID')获取,这个值在会话存续期间不会变,而且不同用户的会话ID绝对不会重复,完美解决多用户并发的匹配问题。

步骤1:给日志表新增会话ID列

如果你的LOG_TABLE还没有这个字段,先执行新增:

ALTER TABLE USER_NAME.LOG_TABLE 
ADD SESSION_ID NUMBER NOT NULL;

步骤2:修改PROC_BEGIN,插入时带上会话ID

在PROC_BEGIN插入日志记录的时候,把当前会话ID也存进去:

INSERT INTO USER_NAME.LOG_TABLE (
    ID_DATE, 
    PROC_NAME, 
    TABLE_NAME, 
    PROC_START_TIME,
    SESSION_ID,
    -- 其他需要的列(比如RCRD_INSRT_DATE等)
) VALUES (
    p_date,
    v_owner||'.'||v_caller,
    P_TABLE_NAME,
    v_start_time,
    SYS_CONTEXT('USERENV','SESSIONID'),
    sysdate -- 对应RCRD_INSRT_DATE
);

步骤3:修改PROC_END的UPDATE语句,加入会话ID条件

把你原来的UPDATE语句加上SESSION_ID的判断,这样就能精准定位到当前会话插入的那条记录:

UPDATE USER_NAME.LOG_TABLE
SET ROW_COUNT = v_row_count,
    PROC_END_TIME = v_end_time,
    PROC_NAME = v_owner||'.'||v_caller,
    RUN_TIME_SECS = (v_end_time - v_start_time )*24*60*60,
    RCRD_INSRT_DATE = sysdate
WHERE ID_DATE = p_date 
  AND PROC_NAME = v_owner||'.'||v_caller 
  AND TABLE_NAME = P_TABLE_NAME
  AND SESSION_ID = SYS_CONTEXT('USERENV','SESSIONID'); -- 这行是核心!

这样一来,不管有多少用户同时跑同一个存储过程,每个会话只会更新自己插入的那条日志记录,完全不会串线。

方法二:自定义请求ID(更灵活的方案)

如果你的ETL流程需要跨会话追踪请求,或者不想依赖Oracle的会话ID,可以自己生成唯一的请求ID,通过参数传递给PROC_BEGIN和PROC_END:

步骤1:创建一个生成请求ID的序列

CREATE SEQUENCE LOG_REQUEST_SEQ 
START WITH 1 
INCREMENT BY 1 
NOCYCLE;

步骤2:在调用存储过程时生成请求ID并传递

修改你的PROC_DO_SOMETHING,先获取请求ID,再传给日志过程:

PROCEDURE PROC_DO_SOMETHING IS
    v_request_id NUMBER;
    -- 其他变量声明
BEGIN
    -- 生成唯一请求ID
    v_request_id := LOG_REQUEST_SEQ.NEXTVAL;
    
    -- 把请求ID传给PROC_BEGIN
    PKG_ETL_LOGGER.PROC_BEGIN(parameters, v_request_id); 
    
    -- 执行你的业务代码...
    
    -- 把请求ID和行计数传给PROC_END
    PKG_ETL_LOGGER.PROC_END(parameters, v_request_id, v_row_count);
END;

步骤3:修改日志过程的逻辑

  • PROC_BEGIN插入日志时,把v_request_id存入新增的REQUEST_ID列(需要先给LOG_TABLE加这个列)
  • PROC_END更新时,WHERE条件加上REQUEST_ID = v_request_id,这样就能精准匹配到对应的日志记录

这个方案的好处是,就算会话意外断开,你也能通过请求ID追踪整个请求的日志,适合复杂的ETL调度场景。

关键提醒

别再用SYSDATE、过程名这类容易重复的字段作为匹配条件了!在多用户并发的场景下,这些字段的重复率极高,根本无法保证精准匹配。必须用会话级或请求级的唯一标识,才能从根源上解决重复记录的问题。

备注:内容来源于stack exchange,提问作者Gustafsson Newad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 07:48:02