需求生成:在业务系统中,有一个一步“取号”的过程,就是从其他服务器同步一些数据到数据库的目标表中。在这个过程中,有可能出现多人同时抽号,相互影响的情况。有测试者反映,原本抽取的数字偶尔会莫名其妙丢失,有时还会反复出现。这个问题肯定是逻辑问题和并行问题引起的!但是他们提出了一个简单的需求:我想知道数据什么时候删除,什么时候插入。我需要监控“桌子的每一次变化”!技术选择:首先想到的是触发器,这样可以在不涉及业务系统代码的情况下实现监控。触发器分为“语句级触发器”和“行级触发器”。在语句级别,每条语句执行前后都会触发一个操作。如果我在每条SQL语句执行完之后,把表名、时间、受影响的行都写到记录表里就可以了。但是问题是语句触发器中,获取不到语句的行数,触发器中sql%rowcount报错。只能使用行级触发器来统计行数!代码结构:整个监控数据行的功能包括:日志表、包、序列。日志表:记录目标表的名称、SQL执行的起止时间、受影响的行数,监控数据行上的一些列信息。封装:主要是3个存储过程,statementstart存储过程:使用关联数组记录目标表名和开始时间,其他值清零。行操作存储过程:关联数组对应的记录数加1数组目标表。语句结束存储过程:将关联数组目标表中的统计信息写入日志表。序列:用于生成日志表的主键代码:日志表和序列:createtableT_CSLOG(n_idNUMBERnotnull,tblnameVARCHAR2(30)notnull,sj1DATE,sj2DATE,i_hsNUMBER,u_hsNUMBER,d_hsNUMBER,portcodeCLOB,startrqDATE,endrqDATE,bzVARCHAR2(100),nNUMBER)createindexIDX_T_CSLOG1onT_CSLOG(TBLNAME,SJ1,SJ2)altertableT_CSLOGaddconstraintPRIKEY_T_CSLOGprimarykey(N_ID)createsequenceSEQ_T_CSLOGminvalue1maxvalue99999999999startwith1incrementby1cache20cycle;包代码:--包头createorreplacepackagepck_cslogis--声明一个关联数组类型,它就是日志表的关联数组typecslog_typeistableoft_cslog%rowtypeindexbyt_cslog.tblname%type;--声明这个关联数组的variable.cslog_tblcslog_type;--Thestatementstarts.procedureonbegin_cs(v_tblnamet_cslog.tblname%type,v_typevarchar2);--rowoperationprocedureoneeachrow_cs(v_tblnamet_cslog.tblname%type,v_typevarchar2,v_codevarchar2:='',v_rqdate:='');--Thestatementendsandiswrittentothelogtable.procedureonend_cs(v_tblnamet_cslog.tblname%type,v_typevarchar2);endpck_cslog;--packagebodycreateorreplacepackagebodypck_cslogis--私有方法,将关联数组中的一条记录写入库);endif;end;--私有方法,清除关联数组procedure中的一条记录clear_cslog(v_tblnamet_cslog.tblname%type)isbeginifcslog_tbl.exists(v_tblname)thencslog_tbl.delete(v_tblname);endif;end;--某条SQL语句的执行开始。v_type:语句类型,i代表insert,u代表update,dprocedureonbegin_cs(v_tblnamet_cslog.tblname%type,v_typevarchar2)isbegin——如果关联数组中不存在,则初始赋值。否则,说明同时有insert和delete语句对目标表进行操作。ifnotcslog_tbl.exists(v_tblname)thencslog_tbl(v_tblname).n_id:=seq_t_cslog.nextval;cslog_tbl(v_tblname).tblname:=v_tblname;cslog_tbl(v_tblname).sj1:=sysdate;cslog_tbl(v_tblname).sj2:=null;cslog_tbl(v_tblname).i_hs:=0;cslog_tbl(v_tblname).u_hs:=0;cslog_tbl(v_tblname).d_hs:=0;cslog_tbl(v_tblname).portcode:='';--开始给一个空格cslog_tbl(v_tblname)。startrq:=to_date('9999','yyyy');cslog_tbl(v_tblname).endrq:=to_date('1900','yyyy');cslog_tbl(v_tblname).n:=0;endif;cslog_tbl(v_tblname)。bz:=cslog_tbl(v_tblname).bz||v_type||',';----输入第一条语句,显示1。如果以后并行化,该值会增加。cslog_tbl(v_tblname).n:=cslog_tbl(v_tblname).n+1;end;--对每一行进行操作。procedureoneachrow_cs(v_tblnamet_cslog.tblname%type,v_typevarchar2,v_codevarchar2:='',v_rqdate:='')isbeginifcslog_tbl.exists(v_tblname)then--行号、代码、起止时间ifv_type='i'thencslog_tbl(v_tblname)。i_hs:=cslog_tbl(v_tblname).i_hs+1;elsifv_type='u'thencslog_tbl(v_tblname).u_hs:=cslog_tbl(v_tblname).u_hs+1;elsifv_type='d'thencslog_tbl(v_tblname).d_hs:=cslog_tbl(v_tblname).d_hs+1;endif;ifv_codeisnotnulllandinstr(cslog_tbl(v_tblname).portcode,v_code)=0thencslog_tbl(v_tblname).portcode:=cslog_tbl(v_tblname).portcode||','||v_code;endif;ifv_rqisnotnullthenifv_rq>cslog_tbl(v_tblname)).endrqthencslog_tbl(v_tblname).endrq:=v_rq;endif;ifv_rq
