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


    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;
    /
  • 相关阅读:
    JMeter压力测试并发测试(入门篇)
    System.currentTimeMillis()的性能问题以及解决方法
    Java日期时间API系列4-----Jdk7及以前的日期时间类的线程安全问题【转】
    使用Apache Commons Chain
    Spring中的InitializingBean接口的使用[转]
    Hash环/一致性Hash原理【转】
    ASP.NET Core 进程内模型和进程外模式
    如何运行多个同名Windows服务实例
    WPF系列 —— 控件添加依赖属性
    WPF系列——简单绑定学习
  • 原文地址:https://www.cnblogs.com/yhq1314/p/10613401.html
Copyright © 2020-2023  润新知