oracle数据库表部分字段双向同步,利用包和触发器实现
oracle数据库表部分字段双向同步,利用包和触发器实现
需求:数据库里面有两张表,结构不完全相同,需要实时同步两张表的部分字段
实现方案:两张表上分别建立触发器进行同步,但是这样操作会有个问题,就会导致触发器循环触发。那么就需要在触发器进行触发前,进行一个判断,如果操作是由触发器引发的,那么就不做操作,反之,执行触发器定义的操作。想要实现这个,我开始考虑过在触发器a里面暂时使触发器b失效,但是发现alter trigger disable不合法;然后看到有人提到在表里面新增一个字段,用来做标识,但是这样需要修改表结构,虽然可以达到要求,但是总觉得不是很好,所以也没有使用;后来通过学习oracle对象,了解到了包的特性,所以决定采用包的方式来实现,利用包的变量来做标识。
/*操作过程中,需要分别执行‘包’,‘函数’,‘触发器’;一次性执行会有问题
操作完成后,注意检查‘包’,‘函数’,‘触发器’状态是否有效*/
--创建包头
create or replace package pk_check_active is
--标识是否为触发器引发
n number :=0;
--获取是否我触发器触发标识,1为触发器触发
function getactive return number;
--设置状态
procedure setactive(n1 in number);
end pk_check_active;
/*这里的/一定不能缺少*/
/
create or replace package body pk_check_active as
function getactive return number is
begin
return n;
end getactive;
procedure setactive(n1 in number) is
begin
n := n1;
end setactive;
end pk_check_active;
--获取guid的方式,采用了8-4-4-4-12的格式
create or replace function Creategs_oid return varchar2
is
guid varchar(64);
result varchar(64);
begin
guid := sys_guid();
result := substr(guid,1,8)||'-'||substr(guid,9,4)||'-'||
substr(guid,13,4)||'-'||substr(guid,17,4)||'-'||substr(guid,21,12);
return (result);
end Creategs_oid;
--触发表tableA
create or replace trigger tr_cs_user after insert or update or delete
on tableA for each row
begin
if pk_check_active.getactive() =1 then
pk_check_active.setactive(2); return;
else
pk_check_active.setactive(1);
end if;
if inserting then
insert into tableB (gs_oid,s_username,s_password) values (Creategs_oid(),:new.name,:new.pass);
elsif updating then
update taableB t set t.s_username=:new.name ,t.s_password=:new.pass where t.s_username=:old.name;
elsif deleting then
delete from tableB t where t.s_username = :old.name;
end if;
pk_check_active.setactive(0);
end;
--获取指定列最大值+1(也是一种id的标识方法,开始没有做成自增字段,所以写触发器的时候需要自己来实现了)
create or replace function GetCSUserID return number
is
result number;
begin
select max(userid)+1 into result from tableA;
return (result);
end GetCSUserID;
--触发tableB
create or replace trigger tr_bs_user after insert or update or delete
on tableB for each row
begin
if pk_check_active.getactive() =1 then
pk_check_active.setactive(2); return;
else
pk_check_active.setactive(1);
end if;
if inserting then
insert into tableA (userid,name,pass,version,useable,remark)
values (GetCSUserID(),:new.s_username,:new.s_password,'SDE.DEFAULT','0','用户自动添加');
elsif updating then
update tableA t set t.name=:new.s_username, t.pass=:new.s_password where t.name=:old.s_username;
elsif deleting then
delete from tableA t where t.name = :old.s_username;
end if;
pk_check_active.setactive(0);
end;
上面的代码,涉及到了包,触发器,函数,存储过程。通过这个小事例,可以了解到常用触发器的用法,同时还有格式化guid的方法,应该对大家还是有一些用处的。这种方式,只能对同一个用户下的表进行同步,如果是跨用户的情况下,这种方式是无效的。
引用"由于package的全局变量在数据库层次上并不可见,所以每个session都可以认为是一个被实例化了的package对象。在session级别上对全局变量执行的赋值操作并不会被其他session看到,很好地体现了数据的封装性。"所以说,通过包的变量来控制,必须是在一个session下。按照我的理解,如果采用ado方式,那么一个连接就算是一个session。
参考内容:http://www.zzzyk.com/database/201203/123813.html
参考内容:http://www.zzzyk.com/database/201203/123813.html