把db1.A表的数据通过streams同步到db2.A表中,db2.A中有一个trigger用于记录一些log信息,问题一是:当通过streams同步过来的数据,不会触发db2.A上的触发器,解决方法是在db2.A设置一下参数:
exec dbms_ddl.set_trigger_firing_property ('testuser', 'TR1_table_A', FALSE);
这个参数默认是true。设置好了,就可以触发db2.A上的触发器了。但问题二是:这个触发器里面的user值无法得到,但其它的如sysdate则正常。而且如果是手工地在db2.A中插入一条数据,则user值则能得到。请问各位,通过streams同步过来的数据,触发器里不能得到这个user值吗?这是db2.A上的触发器的SQL:
CREATE OR REPLACE TRIGGER TR1_table_A BEFORE UPDATE OR INSERT ON A FOR EACH ROW
BEGIN   IF dbms_ddl.is_trigger_fire_once('dms', 'TR1_table_A') THEN
    insert into test1 values('true', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS'));
  ELSE
    insert into test1 values('false', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS'));
  END IF;

IF USER IS NULL THEN
   insert into test2 values('USER IS NULL', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS'));
ELSE  
   insert into test2 values(USER, to_char(sysdate,'DD/MM/YYYY HH24:MI:SS'));
END IF;
END;

解决方案 »

  1.   

    可以换一种思维来实现:
    1.以sysdba用户创建同义词(synonym);
    2.conn user2/pwd2@str2;
    create table test as select * from user1.test where 1=1;
    3.如果实时性较强,可以制作一下脚本,将上述过程写入一个存贮过程中。使用JOB,每5分钟执行一次。
      

  2.   

    如果db1.A和db2.A在相同的服务器上,仅需要在user2下:select * from user1.A;
    如果db1.A和db2.A在不同的服务器上,则建立db_link1后,在user2下:select * from A@db_link1;
      

  3.   

    谢谢,BlueskyWide。哦,情况是这样的,由于对系统的高可用性要求比较高,我们用streams是必须的,是基本前提条件,所有的业务都是基于streams基础上来开展的,现在遇到的是其中的一个技术问题:
      通过streams同步过来的数据,为何在目标端db的表trigger中无法读取到user变量的值?
      

  4.   

    改成这样试下:
    CREATE OR REPLACE TRIGGER TR1_table_A BEFORE UPDATE OR INSERT ON A FOR EACH ROW 
    BEGIN   IF dbms_ddl.is_trigger_fire_once('dms', 'TR1_table_A') THEN 
        insert into test1 values('true', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS')); 
      ELSE 
        insert into test1 values('false', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS')); 
      END IF;   insert into test2 values(ora_login_user, to_char(sysdate,'DD/MM/YYYY HH24:MI:SS')); END;关键是用ora_login_user系统函数
      

  5.   

    试过了,ora_login_user同USER一样都为空,同时试了ora_client_ip_address也为空。
    但ora_database_name和ora_instance_num都是能得到的。难道streams过来的数据,都通过自已的渠道,而不产生user,ora_login_user,ora_client_ip_address吗?
      

  6.   

    查了一下: 
    IS_TRIGGER_FIRE_ONCE:检测特定的DML或DDL触发器是否只触发一次
    语法:DBMS_DDL.IS_TRIGGER_FIRE_ONCE( trigger_owner IN VARCHAR2,--触发器所有者
                                              trigger_name IN VARCHAR2--触发器名); 
           RETURN BOOLEAN;--返回为TRUE则表示触发器只被触发一次LZ在这里的引用{dbms_ddl.is_trigger_fire_once('dms', 'TR1_table_A')}可能有点问题:
    dms是Oracle用户名吗?如果不是,那么引用错了;
    如果是的话,可以试一下:
    CREATE OR REPLACE TRIGGER TR1_table_A BEFORE UPDATE OR INSERT ON A FOR EACH ROW 
    BEGIN 
      IF dbms_ddl.is_trigger_fire_once('dms', 'TR1_table_A') THEN 
        insert into test1 values('dms', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS')); 
      ELSE 
        insert into test1 values('', to_char(sysdate,'DD/MM/YYYY HH24:MI:SS')); 
      END IF; 
    END;
      

  7.   

    谢谢,BlueskyWide,你可能有些误会了。
    为了让TRIGGER TR1_table_A BEFORE能够多次被触发,需要set_trigger_firing_property=false。
    IF dbms_ddl.is_trigger_fire_once这句话在这里主要是做检测用的。关键点不在这里,可以忽略这段IF ...END IF。(dms是用户名)
    重点是: insert into test2 values(ora_login_user, to_char(sysdate,'DD/MM/YYYY HH24:MI:SS')); 
    这句话里ora_login_user或者user无法得到当前用户值,目前总是null值。
      

  8.   

    还是没有答案,好吧,我把需求在说清楚点,现有三个DB(db_A,db_B,db_C),各有一个表T1。db_A和_dbC中的数据可以通过Streams同步到db_B中,此时数据同步到db_B后是不用做任何处理的。但如果在db_B端手工地插入一条数据时,我们则需要根据一些业务分类,分别把这样的数据传回到db_A或db_C中。所以此时在db_B的T1中要能够区分这条数据的来源是:1 Streams同步过来的,还是2 db_B来身产生的。(db_B相当是一个所有DB数据的全集)目前,我们能根据user为空认定它是1 Streams同步过来的,否则是2 db_B来身产生的。但这种判断为空的作法不严谨,只是试验出来的,我是想确切地知道,是不是对于1就是不能得到user的值,还是说某个地方设的不对?
      

  9.   

    Streams以前没用到过。能否在所有的T1表中增加一个字段User_From,
    当update,insert t1表(使用Trigger)时,自动写入User_From字段,以此可以判断来自于何User。关键是:1.没有解决根本问题;2.T1此类的表多时,以上方法并不合适。是否可以考虑使用Package。
      

  10.   

    for your reference:
    http://www.di.unipi.it/~ghelli/didattica/bdl/B19306_01/server.102/b14228/rep_tags.htm#i1007476