zoukankan      html  css  js  c++  java
  • 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;
    /
  • 相关阅读:
    从网络得到图片数据保存到手机中,
    jni 写一个简单的photoshop
    rman catalog配置简要笔记
    如何利用c中的指针实现两个8bit的数合并为16bit
    使用eclipse远程调试weblogic
    迁移11g Rac中OCR和VOTEDISK
    SQL SERVER导入数据到ORACLE的方法总结
    SQL SERVER如何通过SQL语句获服务器硬件和系统信息
    ORACLE SQL Developer日期显示格式设置
    mysqldump:Couldn't execute 'show create table `tablename`': Table tablename' doesn't exist (1146)
  • 原文地址:https://www.cnblogs.com/wuxun1997/p/9831199.html
Copyright © 2011-2022 走看看