首页 > 数据库开发 > 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。那么有没有跨session的访问的方式呢,问了一下谷歌,是有解决方式,不过我测试了没成功,就不卖弄了,在参考文章里面会提到。


本文固定链接: http://www.devba.com/index.php/archives/595.html | 开发吧

报歉!评论已关闭.