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 ...
随机推荐
- js中的BOM对象
浏览器对象模型(BOM)以 window 对象为依托,表示浏览器窗口以及页面可见区域.同时, window对象还是 ECMAScript 中的 Global 对象,因而所有全局变量和函数都是它的属性, ...
- HTML5 ——web audio API 音乐可视化(一)
使用Web Audio API可以对音频进行分析和操作,最终实现一个音频可视化程序. 最终效果请戳这里; 完整版代码请戳这里,如果还看得过眼,请给一个start⭐ 一.API AudioContext ...
- Asp.net使用powershell管理hyper-v
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- uva 10305 拓扑排序裸题
https://vjudge.net/problem/UVA-10305 目前没学dfs做法,用的队列做法,每次找到一个入度为零的点出队后更新其他点,再加入入度为零的点直到查找完毕,这个题目显然一定有 ...
- Pro C/C++ 编程中值得注意的问题
1.宿主字符串存储Oracle自动补零问题. EXEC SQL BEGIN DECLARE SECTION; unsigned char liId[25]; EXEC SQL END DECLARE ...
- java jprofile
java -agentpath:/opt/jprofiler8/bin/linux-x64/libjprofilerti.so=port=8849,nowait -Xdebug -Xrunjdwp:t ...
- 【poj2155】Matrix(二维树状数组区间更新+单点查询)
Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the ...
- webpack2配置
详细的配置可以参考官网:https://doc.webpack-china.org/guides/ 一开始做项目时都是直接从组里前辈搭建好的脚手架开始写代码,到后来自己写新项目时又是拷贝之前的工程作为 ...
- .net 学习路线感想(转)
从上到大学到现在工作,已经有六年多了,发现学习编程到以开发为工作也是一个挺长的过程的. 大学中,从c语言到java.C#到其他各种语言的学习,还有其他知识的学习如:数据库(oracle.sql Ser ...
- Http权威指南(概述篇总结)
之前的<锋利的jQuery>后面陆续翻完了,实在觉得没什么值得记录的,也就没继续写了,然后看见书架上有 本去年买的<Http权威指南>,其实做web编程的,对于Http协议还是 ...