Oracle存儲過程記錄異常日志


  一般我們會將一些涉及到數據庫的定時任務直接用存儲過程搞定,省去了后端代碼的開發、部署,簡單、快速,但這種方式存在一個弊端——當存儲過程執行出錯了,我們無法感知。解決辦法也簡單,學代碼那樣去捕獲異常、打印日志。

  第一步,建日志表:

create table TBL_WLF_SYS_LOG
(
      S_TIME            VARCHAR2(32) not null,
    S_LEVEL            VARCHAR2(32),
    S_PROCNAME        VARCHAR2(64),
    S_MSG            VARCHAR2(4000),
    S_ADVICE        VARCHAR2(1024)
)
tablespace TBS_WLF_DAT;
-- Add comments to the table 
comment on table TBL_WLF_SYS_LOG
  is '存儲過程日志表';
-- Add comments to the columns 
comment on column TBL_WLF_SYS_LOG.S_TIME
  is '操作時間';
-- Add comments to the columns 
comment on column TBL_WLF_SYS_LOG.S_LEVEL
  is '操作級別';
-- Add comments to the columns 
comment on column TBL_WLF_SYS_LOG.S_PROCNAME
  is '執行存儲過程名稱';
-- Add comments to the columns 
comment on column TBL_WLF_SYS_LOG.S_MSG
  is '錯誤信息';
-- Add comments to the columns 
comment on column TBL_WLF_SYS_LOG.S_ADVICE
  is '建議信息';

  第二步,建日志存儲過程:

CREATE OR REPLACE PROCEDURE VCODE.prc_wlf_sys_writelog(
  i_flag       INTEGER,
  i_id         INTEGER,
  str_procname varchar2,
  str_msg      varchar2,
  str_advice   varchar2
) IS
  -- 操作時間
  str_time   varchar2(32);
  -- 操作級別
  str_level  varchar2(32);
  -- 執行存儲過程名稱
  p_procname varchar2(1024);
  -- 錯誤信息,或者記錄信息
  p_msg      varchar2(1024);
  -- 建議信息
  p_advice   varchar2(1024);

BEGIN
  IF (i_flag = 2 AND i_id >= 1 AND i_id <= 4) THEN
    CASE
      WHEN i_id = 1 THEN
        str_level := 'log';
      WHEN i_id = 2 THEN
        str_level := 'debug';
      WHEN i_id = 3 THEN
        str_level := 'alarm';
      ELSE
        str_level := 'error';
    END CASE;
    p_procname := str_procname;
    p_msg      := str_msg;
    p_advice   := str_advice;
  ELSE
    str_level  := 'error';
    p_procname := 'p_public_writelog';
    p_msg      := 'writelog_error';
    p_advice   := '';
  END IF;

  str_time := to_char(SYSDATE, 'yyyy-mm-dd hh24:mi:ss');

  INSERT INTO tbl_wlf_sys_log
    (s_time, s_level, s_procname, s_msg, s_advice)
  VALUES
    (str_time, str_level, p_procname, p_msg, p_advice);
  COMMIT;
END prc_wlf_sys_writelog;
/

  第三步,在我們業務存儲過程中,調用日志存儲過程:

CREATE OR REPLACE procedure VCODE.PROC_CUSTOM_RECORD_UPDATE
is
  -- debug信息
    v_debugmsg      varchar2(1024);
  -- 錯誤信息
    v_errmsg      varchar2(1024);
  -- 查詢用戶邀請活動信息表 獲取活動開始與結束時間
  cursor ACTIVITY_CUR
    is --聲明顯式游標
      select T.ACTIVITYID,
        T.COUNTSTARTTIME,
        T.COUNTENDTIME
      from vcode.T_INVITE_ACTIVITYINFO T
      where T.HASCOUNTTIME = 1;
  --定義游標變量,該變量的類型為基於游標ACTIVITY_CUR的記錄
  type ACTIVITY_CUR_ROW is table of ACTIVITY_CUR%ROWTYPE; 
    cs_invitestat SYS_REFCURSOR;
  type tp_CUSTOM_RECORD is table of T_INVITER_CUSTOM_RECORD%ROWTYPE;
  va_CUSTOM_RECORD tp_CUSTOM_RECORD;
  ACTIVITY_ID varchar2(50);
  START_TIME  date;
  END_TIME    date;
begin
  -- 存儲過程開始日志
  v_debugmsg := 'VCODE.PROC_CUSTOM_RECORD_UPDATE begin  log- ';
  prc_wlf_sys_writelog(2, 2, 'PROC_CUSTOM_RECORD_UPDATE', v_debugmsg, '');
  --For 循環  遍歷用戶邀請活動信息表,根據活動開始結束時間間隔獲取數據信息
  for ACTIVITY_CUR_ROW in ACTIVITY_CUR
  LOOP
  ACTIVITY_ID := ACTIVITY_CUR_ROW.ACTIVITYID;
    START_TIME  := ACTIVITY_CUR_ROW.COUNTSTARTTIME;
    -- 取當天的最后一秒
    select TRUNC(ACTIVITY_CUR_ROW.COUNTENDTIME+1)-1/(24*3600)
    into END_TIME
    from DUAL;
    -- 根據活動ID,開始時間,結束時間,查詢被邀請人記錄表獲取邀請人激活人數與最后激活時間,查詢獎勵記錄表獲取書券獎勵,並關聯一起。
    open cs_invitestat for 
    SELECT t4.INVITERMSISDN,COUNT(1) AS TOTALACTIVENUMBER,max(t4.ACTIVETIME) AS LASTACTIVETIME,t4.ACTIVITYID,CASE WHEN SUM(t3.PRIZENUM) is null THEN 0 ELSE SUM(t3.PRIZENUM) END  totalTicket  
    FROM (    
      SELECT t1.INVITERMSISDN,t1.INVITEEMSISDN,t1.ACTIVETIME,t1.ACTIVITYID   FROM T_INVITEE_RECORD t1
        WHERE t1.ACTIVITYID=ACTIVITY_ID
                  and t1.ACTIVESTATUS = 1
                  and t1.INVITEETYPE = 0
                  and t1.ACTIVETIME <= END_TIME
                  and t1.ACTIVETIME    >= START_TIME ) t4
     LEFT JOIN
     (SELECT t2.INVITERMSISDN,t2.INVITEEMSISDN,SUM(t2.PRIZENUM) PRIZENUM,t2.ACTIVETIME  
      FROM T_INVITING_AWARDS_RECORD t2
       WHERE t2.PRIZETYPE=3 AND t2.ISSEND IN (0,1,2,3,10)
            AND t2.ACTIVITYID=ACTIVITY_ID
            and t2.ACTIVETIME <= END_TIME
            and t2.ACTIVETIME    >= START_TIME
            and t2.REWARDTYPE = 0 
            group by t2.ACTIVETIME,t2.INVITEEMSISDN,t2.INVITERMSISDN) t3
    ON t4.INVITERMSISDN=t3.INVITERMSISDN  AND t4.INVITEEMSISDN=t3.INVITEEMSISDN   AND   t4.ACTIVETIME=t3.ACTIVETIME 
    group by t4.ACTIVITYID,t4.INVITERMSISDN 
    ORDER BY TOTALACTIVENUMBER desc,LASTACTIVETIME ASC;
    fetch cs_invitestat bulk collect into va_CUSTOM_RECORD limit 500;
    -- 遍歷結果,並插入T_INVITER_CUSTOM_RECORD 自定義排行表中,如果存在數據則更新(邀請人、活動ID相同),不存在則插入
    forall i in 1..va_CUSTOM_RECORD.count
    merge into vcode.T_INVITER_CUSTOM_RECORD T5
      using (select * from dual)
      on (INVITERMSISDN = va_CUSTOM_RECORD(i).INVITERMSISDN AND ACTIVITYID=va_CUSTOM_RECORD(i).ACTIVITYID)
    when matched then
        update
          set TOTALACTIVENUMBER      =va_CUSTOM_RECORD(i).TOTALACTIVENUMBER,
            LASTACTIVETIME           =va_CUSTOM_RECORD(i).LASTACTIVETIME,
            TOTALTICKET           =va_CUSTOM_RECORD(i).TOTALTICKET
          where T5.TOTALACTIVENUMBER!=va_CUSTOM_RECORD(i).TOTALACTIVENUMBER OR T5.TOTALTICKET!=va_CUSTOM_RECORD(i).TOTALTICKET
    when not matched then
        insert
          (
            INVITERMSISDN,
            TOTALACTIVENUMBER,
            LASTACTIVETIME,
            ACTIVITYID,
            TOTALTICKET
          )
          values
          (
            va_CUSTOM_RECORD(i).INVITERMSISDN,
            va_CUSTOM_RECORD(i).TOTALACTIVENUMBER,
            va_CUSTOM_RECORD(i).LASTACTIVETIME,
            va_CUSTOM_RECORD(i).ACTIVITYID,
            va_CUSTOM_RECORD(i).TOTALTICKET
          );
        commit;
  end LOOP;
  -- 存儲過程開始日志
  v_debugmsg := 'VCODE.PROC_CUSTOM_RECORD_UPDATE end  log- ';
  prc_wlf_sys_writelog(2, 2, 'PROC_CUSTOM_RECORD_UPDATE', v_debugmsg, '');
exception
  when others then
    begin
      rollback;
      v_errmsg := 'sqlexception~~sqlcode:' || to_char(sqlcode) ||
                  ' sqlstate:' || substr(sqlerrm, 1, 512);
      prc_wlf_sys_writelog(2, 4, 'PROC_CUSTOM_RECORD_UPDATE', v_errmsg, '');
    end;
end;
/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM