首页 > 数据库技术 > 详细

PL/SQL 训练07--发现问题

时间:2019-03-28 11:35:27      阅读:138      评论:0      收藏:0      [点我收藏+]
drop table ma_schedue_task ;

---test_task(:1,:2)
create table ma_schedue_task(
created_by varchar2(100) default system not null,
created_date date default sysdate not null,
updated_by  varchar2(100) default system not null,
updated_date date default sysdate not null,
id_ma_schedue_task varchar2(32) default sys_guid() not null,
procedure_name varchar2(100),
task_months number default 0 not null,
task_days  number default 0 not null,
task_hours number default 0 not null ,
task_minutes number default 0 not null,
first_time   date ,
prev_time date,
next_time date,
is_effected varchar2(2) default N not null,
has_param varchar2(2) default N not null,
thread_num number default 1 not null,
task_priority number default 100 not null
);
comment on table  ma_schedue_task is 任务配置表;

comment on column ma_schedue_task.created_by is 创建人;

comment on column ma_schedue_task.created_date is 创建时间;

comment on column ma_schedue_task.updated_by is 更新人;

comment on column ma_schedue_task.updated_date is 更新时间;

comment on column ma_schedue_task.id_ma_schedue_task is 主键;

comment on column ma_schedue_task.procedure_name is 过程名,可带参数;

comment on column ma_schedue_task.task_months is 频率:月;

comment on column ma_schedue_task.task_days is 频率:天;

comment on column ma_schedue_task.task_hours is 频率:时;

comment on column ma_schedue_task.task_minutes is 频率:分钟;

comment on column ma_schedue_task.first_time is 首次执行时间;

comment on column ma_schedue_task.prev_time is 上次执行时间;

comment on column ma_schedue_task.next_time is 下次执行时间;

comment on column ma_schedue_task.is_effected is 是否生效:N-否,Y-是;

comment on column ma_schedue_task.has_param is 是否带有入参:N-否,Y-是;

comment on column ma_schedue_task.thread_num is 线程数;

comment on column ma_schedue_task.task_priority is 优先级;

create index idx_id_ma_schedue_task on ma_schedue_task(id_ma_schedue_task) initrans 16;

alter table ma_schedue_task add constraint pk_id_ma_schedue_task primary key(id_ma_schedue_task) using index idx_id_ma_schedue_task;


drop table ma_schedue_param ;

create table ma_schedue_param(
created_by varchar2(100) default system not null,
created_date date default sysdate not null,
updated_by  varchar2(100) default system not null,
updated_date date default sysdate not null,
id_ma_schedue_param varchar2(32) default sys_guid() not null,
id_ma_schedue_task varchar2(32),
param_order number,
param_value varchar2(100),
param_group number,
run_status varchar2(2)

);
comment on table  ma_schedue_param is 任务配置表;

comment on column ma_schedue_param.created_by is 创建人;

comment on column ma_schedue_param.created_date is 创建时间;

comment on column ma_schedue_param.updated_by is 更新人;

comment on column ma_schedue_param.updated_date is 更新时间;

comment on column ma_schedue_param.id_ma_schedue_param is 主键;

comment on column ma_schedue_param.id_ma_schedue_task is 关联任务表ID;

comment on column ma_schedue_param.param_order is 参数顺序;

comment on column ma_schedue_param.param_value is 参数值;

comment on column ma_schedue_param.param_group is 参数组别,指定那些参数是一起执行的;

comment on column ma_schedue_param.run_status is 状态:W-等待执行,R-执行中,E-执行失败,S-执行成功;

create index idx_id_ma_schedue_param on ma_schedue_param(id_ma_schedue_param) initrans 16;

alter table ma_schedue_param add constraint pk_id_ma_schedue_param primary key(id_ma_schedue_param) using index idx_id_ma_schedue_param;

测试

--测试不含参数的类型
create or replace procedure test_task is 

 begin 
   dbms_output.put_line(hi,test_task);
end test_task;

DELETE FROM MA_SCHEDUE_TASK WHERE 1=1;
insert into ma_schedue_task(procedure_name,task_days,first_time,has_param,thread_num,is_effected)
values(test_task,1,sysdate-2/24,N,1,Y);
COMMIT;


DELETE FROM MA_SCHEDUE_TASK WHERE 1=1;
insert into ma_schedue_task(procedure_name,task_months,first_time,has_param,thread_num,is_effected)
values(test_task,1,sysdate-2/24,N,1,Y);
COMMIT;


DELETE FROM MA_SCHEDUE_TASK WHERE 1=1;
insert into ma_schedue_task(procedure_name,Task_Hours,first_time,has_param,thread_num,is_effected)
values(test_task,1,sysdate-2/24,N,1,Y);
COMMIT;

DELETE FROM MA_SCHEDUE_TASK WHERE 1=1;
insert into ma_schedue_task(procedure_name,Task_Minutes,first_time,has_param,thread_num,is_effected)
values(test_task,30,sysdate-2/24,N,1,Y);
COMMIT;

--测试含了入参的类型
create or replace procedure test_task_param(i_name in varchar2,i_point in varchar2) is 

begin 
  dbms_output.put_line(i_name||积分||i_point);
end test_task_param;

declare
  v_task_id varchar2(32);
begin
  
  --select sys_guid() into v_task_id ;
delete  from ma_schedue_task;
delete from ma_schedue_param;
  
  insert into ma_schedue_task
    (procedure_name,
     task_days,
     first_time,
     has_param,
     thread_num,
     is_effected)
  values
    (test_task_param(:1,:2), 1, sysdate - 2 / 24, Y, 1, Y)
  returning ID_MA_SCHEDUE_TASK into v_task_id;

  insert into ma_schedue_param
    (id_ma_schedue_task, param_order, param_value, param_group, run_status)
  values
    (v_task_id, 1, 乱世佳人, 1, W);

  insert into ma_schedue_param
    (id_ma_schedue_task, param_order, param_value, param_group, run_status)
  values
    (v_task_id, 2, 10000, 1, W);
end;
/

select * from ma_schedue_task;
select * from ma_schedue_param;


declare
begin
  pkg_schedue_task.dispatch_task;

end;
/

select * from ma_error_log

任务调度

--grant DEBUG CONNECT SESSION to scott;   sys;change_on_install as sysdba
create or replace package pkg_schedue_task is  
 
     procedure scan_task(i_current_time in date,o_ref out sys_refcursor);
     procedure exec_task( i_task_id in varchar2);
     procedure dispatch_task;
     procedure add_task (i_record in ma_schedue_task %rowtype); --配置无参数的方法
     procedure add_task (i_record in ma_schedue_task %rowtype,i_param in ma_schedue_param %rowtype); --配置带参数的方法
     
end pkg_schedue_task;
/


create or replace package body pkg_schedue_task is  
 
     
     procedure dispatch_task is
     
       v_ref  sys_refcursor;
       v_task ma_utils.ma_task_record;
     begin
       scan_task(sysdate, v_ref);
       loop
         fetch v_ref
           into v_task;
         exit when v_ref%notfound;
         exec_task(v_task.task_id);
       end loop;
       close v_ref;
     end dispatch_task;
     
     --扫描需要执行的任务
     
     procedure scan_task(i_current_time date, o_ref out sys_refcursor) is
     
     begin
     
       open o_ref for
         select t.id_ma_schedue_task, t.thread_num
           from ma_schedue_task t
          where t.is_effected = Y
            and ((t.first_time <= i_current_time and t.next_time is null) or
                (t.next_time is not null and t.next_time <= i_current_time))
          order by t.task_priority asc;
     
     end scan_task;
     --执行任务
     procedure exec_task(i_task_id in varchar2) is
     
       v_task ma_schedue_task%rowtype;
       v_no_task_exp exception;
       v_task_no_param_exp exception;
       ls_pn          varchar2(1000) := pkg_schedue_task.exec_task;
       v_current_time date;
       v_next_time    date;
       v_group        ma_schedue_param.param_group%type;
       v_sql          varchar2(4000);
       v_cur          number;
       v_result       number;
     begin
     
       <<get_task>>
       begin
         --获取任务信息
         select *
           into v_task
           from ma_schedue_task r
          where r.id_ma_schedue_task = i_task_id
            and r.is_effected = Y
            and rownum =1;
       exception
         when no_data_found then
           raise v_no_task_exp;
       end get_task;
       --获取任务下次执行时间,如果是第一次执行,则去初次执行时间
       select decode(v_task.next_time,
                     null,
                     v_task.first_time,
                     v_task.next_time)
         into v_current_time
         from dual;
       --根据设置的频度修改下次执行时间
       v_next_time := v_current_time + v_task.TASK_MINUTES / (24 * 60) +
                      v_task.TASK_hours / 24 + v_task.TASK_DAYS;
       v_next_time := add_months(v_next_time, v_task.task_months);
     
       update ma_schedue_task t
          set t.next_time = v_next_time, t.prev_time = sysdate
        where t.id_ma_schedue_task = i_task_id;
       commit;
       --如果任务不带参数,则直接过程,但此处存在SQL注入的可能
       if v_task.has_param = N then
         ma_utils.exec_plsql_block(v_task.PROCEDURE_NAME);
         return;
       end if ;
       --获取处于等待状态的最小参数分组值
       select min(r.param_group)
         into v_group
         from ma_schedue_param r
        where r.id_ma_schedue_task = i_task_id
          and r.run_status = W;
       if v_group is null then
         raise v_task_no_param_exp;
       end if;
       update ma_schedue_param r
          set r.run_status = R
        where r.id_ma_schedue_task = i_task_id
          and r.param_group = v_group
          and r.run_status = W;
       commit;
     
       v_sql :=  begin  || rtrim(v_task.procedure_name, ;) || ;end;;

       v_cur := dbms_sql.open_cursor;
       dbms_sql.parse(v_cur, v_sql, dbms_sql.native);
       --绑定参数
       for param in (select r.param_order, r.param_value
                       from ma_schedue_param r
                      where r.id_ma_schedue_task = i_task_id
                        and r.param_group = v_group
                        and r.run_status = R
                      order by param_order) loop
         dbms_sql.bind_variable(v_cur,
                                : || param.param_order,
                                param.param_value);
       end loop;
       v_result := dbms_sql.execute(v_cur);
       dbms_sql.close_cursor(v_cur);
     
       update ma_schedue_param r
          set r.run_status = S
        where r.id_ma_schedue_task = i_task_id
          and r.param_group = v_group
          and r.run_status = R;
       commit;
     
     exception
       when v_no_task_exp then
         ma_utils.add_error_log(ls_pn, i_task_id || 任务不存在, INFO);
       when v_task_no_param_exp then
         ma_utils.add_error_log(ls_pn,
                                i_task_id || 任务没有配置实参值,
                                ERROR);
       when others then
            update ma_schedue_param r
              set r.run_status = E
            where r.id_ma_schedue_task = i_task_id
              and r.param_group = v_group
              and r.run_status = R;
           commit;
         ma_utils.add_error_log(ls_pn,
                                i_task_id || substr(sqlerrm, 1, 300),
                                ERROR);
     end exec_task;
     

end pkg_schedue_task;
/

错误日志

drop table ma_error_log ;
---错误日志表
create table ma_error_log(
created_by varchar2(100) default system not null,
created_date date default sysdate not null,
updated_by  varchar2(100) default system not null,
updated_date date default sysdate not null,
id_ma_error_log varchar2(32) default sys_guid() not null,
procedure_name varchar2(100),
error_msg  varchar2(2500),
error_level varchar2(30)
);
comment on table  ma_error_log is 任务配置表;

comment on column ma_error_log.created_by is 创建人;

comment on column ma_error_log.created_date is 创建时间;

comment on column ma_error_log.updated_by is 更新人;

comment on column ma_error_log.updated_date is 更新时间;

comment on column ma_error_log.id_ma_error_log is 主键;

comment on column ma_error_log.procedure_name is 发生异常时调用的方法;

comment on column ma_error_log.error_msg is 错误信息;

comment on column ma_error_log.error_level is 错误级别:info,important,error;


create index idx_id_ma_error_log on ma_error_log(id_ma_error_log) initrans 16;
create index idx_error_created_date on  ma_error_log(created_date) initrans 16;

alter table ma_error_log add constraint pk_id_ma_error_log primary key(id_ma_error_log) using index idx_id_ma_error_log;

--创建工具包
create or replace package ma_utils  is 

   type ma_task_record is record(task_id varchar2(32),thread_num number);
   
   procedure add_error_log(i_procedure_name in varchar2,
                           i_error_msg in  varchar2,
                           i_error_level in varchar2);
  

   procedure exec_plsql_block(i_plsql in varchar2);

end ma_utils;
/

create or replace package body ma_utils is

  procedure add_error_log(i_procedure_name in varchar2,
                          i_error_msg      in varchar2,
                          i_error_level    in varchar2) is
    pragma autonomous_transaction;
  begin
  
    insert into ma_error_log
      (procedure_name, error_msg, error_level)
    values
      (i_procedure_name, i_error_msg, i_error_level);
  
    commit;
  exception
    when others then
      rollback;
    
  end add_error_log;

  procedure exec_plsql_block(i_plsql in varchar2) is
  begin
    execute immediate begin  || rtrim(i_plsql, ;) ||  ; end ;;
  end exec_plsql_block;

end ma_utils;
/

 

PL/SQL 训练07--发现问题

原文:https://www.cnblogs.com/yhq1314/p/10613401.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!