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, '', 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--发现问题的更多相关文章

  1. PL/SQL 训练03 --异常

    --程序员在开发的时候,经常天真的认为这个世界是完美的,用户如同自己般聪明,总能按照自己设想的方式--操作系统输入数据.但残酷的事实告诉我们,这是不可能的事情,用户总会跟我们相反的方式操作系统--于是 ...

  2. PL/SQL 训练13--plsql 优化

    --数据缓存技术 --PGA和SGA---SGA:系统全局区域--PGA:Process Global Area是为每个连接到Oracle的用户进程保留的内存. ---PLSQL从PGA获取信息的速度 ...

  3. PL/SQL 训练12--动态sql和绑定变量

    --什么是动态SQL?动态PL/SQL--动态SQL是指在运行时刻才构建执行的SQL语句--动态PL/SQL是指整个PL/SQL代码块都是动态构建,然后再编译执行 --动态SQL来可以用来干什么? - ...

  4. PL/SQL 训练11--包

    --所谓包,就是把一组PL/SQL的代码元素组织在一个命名空间下.--一种可以把程序或者其他的PL/SQL元素比如游标.类型.变量的组织结构在一起的结构(包括逻辑结构和物理结构)--包提供了非常重要的 ...

  5. PL/SQL 训练10--io及文件操作

    多数程序只需要通过SQL和底层数据库进行交互--有些情况,不可避免的还是会有一些场景,需要从PL/SQL给外部环境发送信息--或是从一些外部的源读入信息 --这节课介绍下面这些内置包 dbms_out ...

  6. PL/SQL 训练08--触发器

    --什么是触发器呢?--一触即发,某个事件发生时,执行的程序块?--数据库触发器是一个当数据库发生某种事件时作为对这个事件的响应而执行的一个被命名的程序单元 --适合场景--对表的修改做验证--数据库 ...

  7. PL/SQL 训练05--游标

    --隐式游标--通过一个简单的SELECT ...INTO 语句提取一行数据,并放在一个局部变量中,最简单获取数据的途径 --显示游标--可以在声明单元明确的声明一个查询,这样可以在一个或多个程序中打 ...

  8. PL/SQL 训练04--事务

    --pl/sql通过SQL和ORACLE数据库紧密的整合在一起--在pl/sql中可以执行任何操作语句(DML语句),包括INSERT,UPDATE,DELETE,MERGE,也包括查询语句--可否执 ...

  9. PL/SQL 训练02--集合数组

    1. 请列举关联数组.嵌套表.VARRAY三种集合类型的区别区别:1 关联数组只能在plsql中使用,嵌套表,varray可用于sql中,数据库表中的列2 嵌套表,varray必须在使用的时候初始化, ...

  10. PL/SQL 训练01--基础介绍

    --开始介绍变量之前,我们先看下怎么在PLSQL写程序,如下我们写了一个块 declare --声明部分,声明变量 v_name ) :='hello world'; begin --执行区域 dbm ...

随机推荐

  1. 关于Jupyter Notebook默认起始目录设置无效的解决方法

    一.问题描述 今天折腾jupyter的时候,突然觉得起始目录是用户根目录很麻烦,想着把他改成自己的某个文件,按照网上方法折腾半天也还是无效.东点点西看看才发现端倪. [win10以下好像没这个问题,修 ...

  2. LeetCode第[2]题(Java):Add Two Numbers (链表相加)——Medium

    题目难度:Medium 题目: You are given two non-empty linked lists representing two non-negative integers. The ...

  3. 20165332 预备作业三 Linux安装及命令入门

    Linux安装及命令入门 一.安装Linux操作系统 由于做的比较晚,结合大多数同学的经验和娄老师的<基于VirtualBox虚拟机安装Ubuntu图文教程>,整个安装过程还算顺利,唯一遇 ...

  4. 【pat-1074】宇宙无敌加法器(高精度)

    链接:https://www.patest.cn/contests/pat-b-practise/1074 地球人习惯使用十进制数,并且默认一个数字的每一位都是十进制的.而在PAT星人开挂的世界里,每 ...

  5. js获取一周的日期范围

    function getWeek() { this.nowTime = new Date(); this.init = function() { this.dayInWeek = this.nowTi ...

  6. QGrapicsScene类

    概述 QgraphicsScene类为管理大量的2D图形item提供了一个管理界面,做为item的容器,它配合使用QgraphicsView使用来观察items,例如线,矩形,文本或者自定义的item ...

  7. Thrift之c++实例

    一.c++实例 1.下载与安装thrift工具 http://thrift.apache.org/download/ .服务端代码 1).新建vc工程. 2).将上面的文件拷贝到工程目录下,Test_ ...

  8. 关于for循环中是否需要缓存length值的个人总结

    在JS性能优化中,有一个常见的小优化,即 // 不缓存 for (var i = 0; i < arr.length; i++) { ... } // 缓存 var len = arr.leng ...

  9. asp.net core mcroservices 架构之 分布式日志(三):集成kafka

    一 kafka介绍 kafka是基于zookeeper的一个分布式流平台,既然是流,那么大家都能猜到它的存储结构基本上就是线性的了.硬盘大家都知道读写非常的慢,那是因为在随机情况下,线性下,硬盘的读写 ...

  10. webpack新版本4.12应用九(配置文件之使用不同语言进行配置)

    使用不同语言进行配置(configuration languages) 查看原文|编辑此页 webpack 接受以多种编程和数据语言编写的配置文件.支持的文件扩展名列表,可以在 node-interp ...