目的:由于公司数据库权限管理的很严,每次新建表后需要手动授权给相应的用户,并且还要创建同义词。这就很是麻烦。账号一多就特别花时间。所以自己写了两个存储过程和定时JOB来实现动态授权。
需求:A用户访问B用户,A用户可以增删改查B用户所有表(不包括系统表)。A是普通用户,B用户拥有DBA权限,所以我们不能用以下方式授权,这样会把系统表的权限也放出去。
grant select any table to a;
grant all on b.table_name to a;
一、授予A用户访问B用户现有表访问权限
1.新建一个普通用户A。
create user 用户名 identified by "密码" default tablespace 表空间 temporary tablespace temp;
授予A用户resource/connect权限、创建私有同义词权限。
grant create synonym to A;
grant resource,connect to A;
2.授予A用户访问B用户所有表权限,另存为.sql后缀,放在Command里面执行。
select 'GRANT select, insert, update, delete ON B.'|| 表名||' to A;' from user_tables;
创建所有表的私有同义词,在A用户上创建
select 'create synonym '||同义词名称||' for B.'||表名||';' from user_tables where tablespace_name='表空间';
以上操作是针对B用户下现有表授予A用户访问权限。
二、通过JOB定时调用存储过程实现动态授权A用户。
准备:A用户下两张表、两个sequence、两个触发器(可有可无)、一个存储过程、一个定时JOB。B用户一个存储过程、一个定时JOB
两张表可根据自身需求增加相应的字段。
1.A用户
A用户表1
create table CREATE_LOG ( pid INTEGER not null, pobject VARCHAR2(400), sjc VARCHAR2(14) ); alter table CREATE_LOG add primary key (PID);
A用户表2
create table CREATE_OBJECT ( pid INTEGER not null, sobject VARCHAR2(400), sjc VARCHAR2(14) ); alter table NEWINGS_OBJECT add primary key (PID); grant select, insert on CREATE_OBJECT to B; #授权给B用户访问,存储过程里面要用到
sequence是给两张表主键使用的,创建一下就好了。触发器主要是实现主键自增和将空的时间戳赋值。很简单
存储过程
create or replace procedure create_actions is --scount number(10); snum number(10); begin declare cursor cur is select sobject from newings_object where sjc>=to_char(sysdate,'yyyymmdd'); begin for cur_result in cur loop select count(1) into snum from create_log where pobject=cur_result.sobject; if snum=0 then EXECUTE IMMEDIATE 'create synonym '||cur_result.sobject||' for B.'||cur_result.sobject; insert into create_log(pobject) values(cur_result.sobject); commit; end if; end loop; end; end;
定时JOB(A、B用户定时JOB执行时间最好是错开)
declare job number; BEGIN DBMS_JOB.SUBMIT( JOB => job, /*自动生成JOB_ID*/ WHAT => 'create_actions;', /*需要执行的存储过程名称或SQL语句*/ NEXT_DATE => sysdate+3/(24*60), /*初次执行时间-下一个3分钟*/ INTERVAL => 'trunc(sysdate,''mi'')+1/(24*60)' /*每隔1分钟执行一次*/ ); commit; end;
2.B用户
存储过程
create or replace procedure create_action is scount number(10); snum number(10); begin select count(1) into scount from user_objects where to_char(created,'yyyymmddhh24miss')>=to_char(sysdate,'yyyymmdd') and object_type='TABLE'; declare cursor cur is select object_name from user_objects where to_char(created,'yyyymmddhh24miss')>=to_char(sysdate,'yyyymmdd') and object_type='TABLE'; begin for cur_result in cur loop if scount>0 then select count(1) into snum from A.newings_object where sobject=cur_result.object_name; if snum=0 then EXECUTE IMMEDIATE 'grant select,insert,update,delete on B.'||cur_result.object_name||' to A'; --EXECUTE IMMEDIATE 'insert into A.newings_object(sobject) values('||cur_result.object_name||')'; insert into roobbin.newings_object(sobject) values(cur_result.object_name); commit; end if; end if; end loop; end; end;
定时JOB,A、B用户定时JOB执行时间最好是错开
declare job number; BEGIN DBMS_JOB.SUBMIT( JOB => job, /*自动生成JOB_ID*/ WHAT => 'create_action;', /*需要执行的存储过程名称或SQL语句*/ NEXT_DATE => sysdate+3/(24*60), /*初次执行时间-下一个3分钟*/ INTERVAL => 'trunc(sysdate,''mi'')+1/(24*60)' /*每隔1分钟执行一次*/ ); commit; end;
附:user_jobs主要字段说明
列名 数据类型 解释 JOB NUMBER 任务的唯一标示号 LOG_USER VARCHAR2(30) 提交任务的用户 PRIV_USER VARCHAR2(30) 赋予任务权限的用户 SCHEMA_USER VARCHAR2(30) 对任务作语法分析的用户模式 LAST_DATE DATE 最后一次成功运行任务的时间 LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小时,分钟和秒 THIS_DATE DATE 正在运行任务的开始时间,如果没有运行任务则为null THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小时,分钟和秒 NEXT_DATE DATE 下一次定时运行任务的时间 NEXT_SEC VARCHAR2(8) 如HH24:MM:SS格式的next_date日期的小时,分钟和秒 TOTAL_TIME NUMBER 该任务运行所需要的总时间,单位为秒 BROKEN VARCHAR2(1) 标志参数,Y标示任务中断,以后不会运行 INTERVAL VARCHAR2(200) 用于计算下一运行时间的表达式 FAILURES NUMBER 任务运行连续没有成功的次数 WHAT VARCHAR2(2000) 执行任务的PL/SQL块
INTERVAL常用参数示例
每天午夜12点 ''TRUNC(SYSDATE + 1)'' 每天早上8点30分 ''TRUNC(SYSDATE + 1) + (8*60+30)/(24*60)'' 每星期二中午12点 ''NEXT_DAY(TRUNC(SYSDATE ), ''''TUESDAY'''' ) + 12/24'' 每个月第一天的午夜12点 ''TRUNC(LAST_DAY(SYSDATE ) + 1)'' 每个季度最后一天的晚上11点 ''TRUNC(ADD_MONTHS(SYSDATE + 2/24, 3 ), ''Q'' ) -1/24'' 每星期六和日早上6点10分 ''TRUNC(LEAST(NEXT_DAY(SYSDATE, ''''SATURDAY"), NEXT_DAY(SYSDATE, "SUNDAY"))) + (6×60+10)/(24×60)'' 每3秒钟执行一次 'sysdate+3/(24*60*60)' 每2分钟执行一次 'sysdate+2/(24*60)' 1:每分钟执行 Interval => TRUNC(sysdate,'mi') + 1/ (24*60) --每分钟执行 interval => 'sysdate+1/(24*60)' --每分钟执行 interval => 'sysdate+1' --每天 interval => 'sysdate+1/24' --每小时 interval => 'sysdate+2/24*60' --每2分钟 interval => 'sysdate+30/24*60*60' --每30秒 2:每天定时执行 Interval => TRUNC(sysdate+1) --每天凌晨0点执行 Interval => TRUNC(sysdate+1)+1/24 --每天凌晨1点执行 Interval => TRUNC(SYSDATE+1)+(8*60+30)/(24*60) --每天早上8点30分执行 3:每周定时执行 Interval => TRUNC(next_day(sysdate,'星期一'))+1/24 --每周一凌晨1点执行 Interval => TRUNC(next_day(sysdate,1))+2/24 --每周一凌晨2点执行 4:每月定时执行 Interval =>TTRUNC(LAST_DAY(SYSDATE)+1) --每月1日凌晨0点执行 Interval =>TRUNC(LAST_DAY(SYSDATE))+1+1/24 --每月1日凌晨1点执行 5:每季度定时执行 Interval => TRUNC(ADD_MONTHS(SYSDATE,3),'q') --每季度的第一天凌晨0点执行 Interval => TRUNC(ADD_MONTHS(SYSDATE,3),'q') + 1/24 --每季度的第一天凌晨1点执行 Interval => TRUNC(ADD_MONTHS(SYSDATE+ 2/24,3),'q')-1/24 --每季度的最后一天的晚上11点执行 6:每半年定时执行 Interval => ADD_MONTHS(trunc(sysdate,'yyyy'),6)+1/24 --每年7月1日和1月1日凌晨1点 7:每年定时执行 Interval =>ADD_MONTHS(trunc(sysdate,'yyyy'),12)+1/24 --每年1月1日凌晨1点执行
参考博客:https://www.cnblogs.com/Chestnuts/p/7068456.html
大概就是这一个样子,已亲测可以使用。如有需要改进的地方请留言,谢谢!