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, '', 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--发现问题的更多相关文章
- PL/SQL 训练03 --异常
--程序员在开发的时候,经常天真的认为这个世界是完美的,用户如同自己般聪明,总能按照自己设想的方式--操作系统输入数据.但残酷的事实告诉我们,这是不可能的事情,用户总会跟我们相反的方式操作系统--于是 ...
- PL/SQL 训练13--plsql 优化
--数据缓存技术 --PGA和SGA---SGA:系统全局区域--PGA:Process Global Area是为每个连接到Oracle的用户进程保留的内存. ---PLSQL从PGA获取信息的速度 ...
- PL/SQL 训练12--动态sql和绑定变量
--什么是动态SQL?动态PL/SQL--动态SQL是指在运行时刻才构建执行的SQL语句--动态PL/SQL是指整个PL/SQL代码块都是动态构建,然后再编译执行 --动态SQL来可以用来干什么? - ...
- PL/SQL 训练11--包
--所谓包,就是把一组PL/SQL的代码元素组织在一个命名空间下.--一种可以把程序或者其他的PL/SQL元素比如游标.类型.变量的组织结构在一起的结构(包括逻辑结构和物理结构)--包提供了非常重要的 ...
- PL/SQL 训练10--io及文件操作
多数程序只需要通过SQL和底层数据库进行交互--有些情况,不可避免的还是会有一些场景,需要从PL/SQL给外部环境发送信息--或是从一些外部的源读入信息 --这节课介绍下面这些内置包 dbms_out ...
- PL/SQL 训练08--触发器
--什么是触发器呢?--一触即发,某个事件发生时,执行的程序块?--数据库触发器是一个当数据库发生某种事件时作为对这个事件的响应而执行的一个被命名的程序单元 --适合场景--对表的修改做验证--数据库 ...
- PL/SQL 训练05--游标
--隐式游标--通过一个简单的SELECT ...INTO 语句提取一行数据,并放在一个局部变量中,最简单获取数据的途径 --显示游标--可以在声明单元明确的声明一个查询,这样可以在一个或多个程序中打 ...
- PL/SQL 训练04--事务
--pl/sql通过SQL和ORACLE数据库紧密的整合在一起--在pl/sql中可以执行任何操作语句(DML语句),包括INSERT,UPDATE,DELETE,MERGE,也包括查询语句--可否执 ...
- PL/SQL 训练02--集合数组
1. 请列举关联数组.嵌套表.VARRAY三种集合类型的区别区别:1 关联数组只能在plsql中使用,嵌套表,varray可用于sql中,数据库表中的列2 嵌套表,varray必须在使用的时候初始化, ...
- PL/SQL 训练01--基础介绍
--开始介绍变量之前,我们先看下怎么在PLSQL写程序,如下我们写了一个块 declare --声明部分,声明变量 v_name ) :='hello world'; begin --执行区域 dbm ...
随机推荐
- JavaScript tips —— 搞定闰年
前言 处理时间时,常常要考虑用户的输入是否合法,其中一个很典型的场景就是平闰年的判断,网上其实有很多类似的算法,但是其实不必那么麻烦,下面我讲讲的我的思路. 规则 公元年数可被4整除为闰年,但是整百( ...
- spring3: Bean的作用域
3.4 Bean的作用域 什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围.而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围. ...
- pxcook-高效易用的自动标注工具, 生成前端代码
1.pxcook.sketch(http://www.fancynode.com.cn/pxcook)
- Mysql的锁机制——待写
发酵独守空房飞杀戮空间爱的色放
- SPI笔记
sclk(serial clock):串行时钟 MOSI(master out slave input) (master 主机) (slave 从机) MISO(master int slave ...
- Java8_00_资源帖
一.官方资料 Java Platform Standard Edition 8 Documentation The Java™ Tutorials Java 8 API 二.精选资料 三.参考资料
- 常用algorithm及其Python实现
冒泡排序 def bubble_sort(li): for i in range(len(li)-1): # i表示第几趟 for j in range(len(li)-i-1): # j表示图中的箭 ...
- Js中分号使用总结
作者:尤雨溪链接:https://www.zhihu.com/question/20298345/answer/49551142来源:知乎著作权归作者所有,转载请联系作者获得授权. 没有应该不应该,只 ...
- Dojo Chart之常用统计图
很多做web的都知道,在很多web系统中会涉及到一些统计图,例如饼状图,柱状图.趋势图.以及叠加图等.提到这儿,做web的都很熟悉的,jquery的highcharts就能搞定所有的涉及到统计图的功能 ...
- cmd 操作WinService
1.运行--〉cmd:打开cmd命令框 2.在命令行里定位到InstallUtil.exe所在的位置 InstallUtil.exe 默认的安装位置是在C:\Windows\Microsoft.NET ...