Oracle存储过程记录异常日志
一般我们会将一些涉及到数据库的定时任务直接用存储过程搞定,省去了后端代码的开发、部署,简单、快速,但这种方式存在一个弊端——当存储过程执行出错了,我们无法感知。解决办法也简单,学代码那样去捕获异常、打印日志。
第一步,建日志表:
create table TBL_WLF_SYS_LOG
(
S_TIME VARCHAR2() not null,
S_LEVEL VARCHAR2(),
S_PROCNAME VARCHAR2(),
S_MSG VARCHAR2(),
S_ADVICE VARCHAR2()
)
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;
/
Oracle存储过程记录异常日志的更多相关文章
- Oracle存储过程记录异常
--建立错误日志表 create table PUB_PROC_ERR_LOG ( LOG_ID NUMBER, MODULE_NAME ), PROC_NAME ), ERR_TIME DATE, ...
- Oracle存储过程中异常Exception的捕捉和处理
Oracle存储过程中异常的捕捉和处理 CREATE OR REPLACE Procedure Proc_error_process ( v_IN in Varchar2, v_OUT Out Var ...
- 项目中oracle存储过程记录——经常使用语法备忘
项目中oracle存储过程记录--经常使用语法备忘 项目中须要写一个oracle存储过程,需求是收集一个复杂查询的内容(涉及到多张表),然后把符合条件的记录插入到目标表中.当中原表之中的一个的日期字段 ...
- oracle存储过程获取异常信息码和异常信息
oracle存储过程,可以通过sqlcode 获取异常编码.通过sqlerrm获取异常信息. 例子: create or replace procedure write2blob(p_id in nu ...
- 在 C# 控制台中记录异常日志并输出
最近做了一个小程序,要求在控制台中记录程序运行的异常并输出到指定的文件夹中,以下是我的具体的程序代码: public static void ErrorLog(Exception ex) { stri ...
- MVC4.0 利用HandleErrorAttribute和log4net实现记录异常日志功能
1.MVC4.0中HandleErrorAttribte已经帮我们处理了异常问题,当我们新建一个非空的MVC项目时候,在FilterConfig中会发现这样的代码 public class Filte ...
- MVC中使用过滤器记录异常日志
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Filte ...
- 在ASP.NET MVC中使用Log4Net记录异常日志,出错时导向到静态页
本篇体验在ASP.NET MVC 4中使用Log4Net记录日志. 通过NuGet安装Log4Net. 需求是:当出错时导向到Error.html静态页面,Log4Net记录错误信息. 大致的思路是: ...
- ASP.NET全局错误处理和异常日志记录以及IIS配置自定义错误页面
应用场景和使用目的 很多时候,我们在访问页面的时候,由于程序异常.系统崩溃会导致出现黄页.在通常的情况下,黄页对于我们来说,帮助是极大的,因为它可以帮助我们知道问题根源,甚至是哪一行代码出现了错误.但 ...
随机推荐
- mongodb安装与权限配置
mongodb下载地址:官方下载IDE工具:Robo 3T:官方下载 windows系统要求64位,最低2g内存,推荐8g内存及以上 安装过程没有需要配置的地方,直接下一步到结束,如果想要方便可以在环 ...
- iptables详解(11):iptables之网络防火墙
我们一起来回顾一下之前的知识,在第一篇介绍iptables的文章中,我们就描述过防火墙的概念,我们说过,防火墙从逻辑上讲,可以分为主机防火墙与网络防火墙. 主机防火墙:针对于单个主机进行防护. 网络防 ...
- C++中几个值得分析的小问题(2)
下面有3个小问题,作为C++ Beginner你一定要知道错在哪里了. 1.派生类到基类的引用或指针转换一定“完美”存在? 一般情况,你很可能会认为:派生类对象的引用或指针转换为基类对象的引用或指针是 ...
- LINUX系统下CIFS文件系统
一.什么是CIFS CIFS(Common Internet File System)文件系统,也叫通用网络文件系统:它可以使一台主机访问远程主机上共享出去的文件.CIFS使用的C/S模式(客户 ...
- react 生命周期图
1. react v16 版本生命周期 2. react v17 (还未发布), 生命周期将被改动,下面红框的部分就是会被删除的部分,注意调整!
- TCP 初步认识
TCP连接的建立---三次握手 第一次握手:客户端TCP首先给服务器端TCP发送一个特殊的TCP数据段. 该数据段不包含应用层数据,并将头部中的SYN位设置为1,所以该数据段被称为SYN数据段. 另外 ...
- 42.zip
最近看linux的解压缩,无意间了解到了一个和压缩率相关的小故事——42.zip 一般我们使用压缩工具的时候,都会用到无损压缩技术,对于无损压缩,算法非常重要,不同的算法实现 的压缩率和速度有很大差别 ...
- TCP 和 UDP 的区别( 面向连接 和 面向无连接 )
第一:TCP 和 UDP 的区别( 面向连接 和 面向无连接 ) TCP---传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才 ...
- 【Git】无法从远程分支pull
随着工作量的增多,接触的新项目,新同事越来越多,发现自己不会的东西好多.有这么一句话:“你所知道的知识就像是一个圆,你会的越多,圆越大,但你接触的未知世界也越大,也就越加觉得自己无知”.原话记不全了, ...
- IOS Number 处理(int-->NSNumber,NSNumber-->nsinteger,string -->double,CGFloat --> dobule)
1 小结: 1)int-->NSNumber:numberWithInt 2)NSNumber-->nsinteger:integerValue 3)string -->double ...