不同数据库不同表结构的oracle数据库定时更新方法

问题描述:数据库B需要数据库A中的某些详细信息,且需要定时更新数据库B的数据,最好能做到实时更新
整体方法描述:通过webService来实现。首先是CLIENT端发送请求到SERVICE端,收到请求后将需要的数据全部打包发送给CLIENT端,CLIENT端收到数据
后插入或更新目标数据库的临时表中,临时表通过触发器来更新或插入到表中,同时更新源数据库中临时表的时间字段信息。
具体方法如下:
1、首先在数据库A中通过建立视图来查找出数据库B需要的字段信息。
此时需注意字段结构要一样。
2、在源数据库A中建立一张临时表
create table t_temp(
t_temp_id number(18) primary key not null,
updatetime datetime,
tablename varchar2(20),
status char(1)
);
3、service 端传送数据方法,为确保数据的安全性,在传送数据的过程中需要对数据进行压缩传送方法
数据打包压缩成一个DataSet后发送给CLIENT 端
数据压缩与解压缩方法:

 public class ZipUnZip
    {
        public static byte[] ZipData(DataSet ds)
        {
            byte[] zipData = null;
            //DataSet ds = LoadUserInfo(q).Copy();
            ds.RemotingFormat = SerializationFormat.Binary;
            BinaryFormatter ser = new BinaryFormatter();
            MemoryStream unMS = new MemoryStream();
            ser.Serialize(unMS, ds);

            byte[] bytes = unMS.ToArray();
            int lenbyte = bytes.Length;

            MemoryStream compMs = new MemoryStream();
            GZipStream compStream = new GZipStream(compMs, CompressionMode.Compress, true);
            compStream.Write(bytes, 0, lenbyte);

            compStream.Close();
            unMS.Close();
            compMs.Close();
            zipData = compMs.ToArray();
            return zipData;
        }

        public static DataSet UnzipData(byte[] da)
        {
            DataSet ds = new DataSet();

            try
            {
                //WS.Service1 wss = new WSZipDemo.WS.Service1();//WebReference
                //byte[] da = wss.getZipData();

                MemoryStream input = new MemoryStream();
                input.Write(da, 0, da.Length);
                input.Position = 0;
                GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true);

                MemoryStream output = new MemoryStream();
                byte[] buff = new byte[4096];
                int read = -1;
                read = gzip.Read(buff, 0, buff.Length);
                while (read > 0)
                {
                    output.Write(buff, 0, read);
                    read = gzip.Read(buff, 0, buff.Length);
                }
                gzip.Close();
                byte[] rebytes = output.ToArray();
                output.Close();
                input.Close();

                MemoryStream ms = new MemoryStream(rebytes);
                BinaryFormatter bf = new BinaryFormatter();
                object obj = bf.Deserialize(ms);
                ds = (DataSet)obj;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
            }
            return ds;
        }

    } 

4、CLIENT端收到数据后,对目标数据库中的临时表进行操作(临时表的结构与正式表结构一样),将数据全部插入到临时表中,

   插入数据到临时表中时, 最好先清空临时表中的信息。(truncate table table_name;)
ds是SERVICE端传送过来的DataSet数据集.
CLIENT 端可调用方法:Boolean b = oracleHelper.GetSqlBulkCopy(ds, oracleConn);

public class OracleHelper
    {
        /// <summary>
        /// 大批量入库处理
        /// </summary>
        /// <param name="dtData"></param>
        /// <returns></returns>
        public Boolean GetSqlBulkCopy(DataSet dsData, OracleConnection conn)
        {
            Boolean bolReturn = false;
            foreach (DataTable dtData in dsData.Tables)
            {
                bolReturn = GetSqlBulkCopyByTable(dtData, conn);
            }
            return bolReturn;
        }

        public Boolean GetSqlBulkCopyByTable(DataTable dtData, OracleConnection oracleConn)
        {
           int BulkCopySize = 500;
            int BulkCopyTimeOut = 1000 * 60 * 60 * 60;
            Boolean bolReturn = false;
            OracleBulkCopy bulkCopy = null;
            try
            {
                bulkCopy = new OracleBulkCopy(oracleConn);
                bulkCopy.DestinationTableName = dtData.TableName + "_TEMP";
                bulkCopy.BatchSize = BulkCopySize;
                bulkCopy.BulkCopyOptions = OracleBulkCopyOptions.UseInternalTransaction;
                bulkCopy.BulkCopyTimeout = BulkCopyTimeOut;
                bulkCopy.WriteToServer(dtData);
                bolReturn = true;
            }
            catch
            {
                bolReturn = false;
                throw;
            }
            finally
            {
                bulkCopy = null;
            }
            return bolReturn;
        }
    }

5、通过临时表触发器来更新或插入目标数据库B中的数据
触发器格式案例如下:

 CREATE OR REPLACE TRIGGER T_TEMP_trg
AFTER INSERT OR UPDATE ON T_TEMP
FOR EACH ROW
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
    resultCount number :=0;
    maxID number :=0;
BEGIN
  -- 查询是否有记录 以此判断是否更新插入
  SELECT count(*) INTO resultCount FROM T_TDJY WHERE YWLSH = :NEW.YWLSH AND YXTYWLSH = :NEW.YXTYWLSH AND BDBH =
    :NEW.BDBH AND BJJE =:NEW.BJJE;
    --下一条记录的ID
  SELECT max(T_TDJY_ID) INTO maxID  FROM T_TDJY;
  --maxID :=maxID+1;
   IF(resultCount=0) THEN
      INSERT INTO T_TDJY VALUES(
        nvl(maxID,0)+1,
 :NEW.YWLSH,
 :NEW.BBH,
 :NEW.XZQH,
 :NEW.YXTYWLSH,
 :NEW.JMRBH,
 :NEW.BDBH,
 :NEW.JMRIP,
 :NEW.BJJE
);
      ELSE
        UPDATE T_TDJY SET
 YWLSH=   :NEW.YWLSH,
 BBH=     :NEW.BBH,
 XZQH=    :NEW.XZQH,
 YXTYWLSH=:NEW.YXTYWLSH,
 JMRBH=   :NEW.JMRBH,
 BDBH=    :NEW.BDBH,
 JMRIP=   :NEW.JMRIP,
 BJJE=    :NEW.BJJE
       WHERE YWLSH = :NEW.YWLSH AND YXTYWLSH = :NEW.YXTYWLSH AND BDBH =:NEW.BDBH AND BJJE =:NEW.BJJE;
       END IF;
      -- DELETE FROM T_TDJY;
  commit;
END;

6、如果不进行一定的处理时,在通过临时表的触发器来进行插入或更新数据目标数据库数据时,会出现 :直接路径不支持使用触发器的错误。
因为OracleBulkCopy类不支持事务处理。
解决方法:
1、将源数据库中的数据插入到目标数据库临时表中时,先将目标数据库中临时表的触发器禁用掉,然后调用下面方法:
Boolean b = oracleHelper.GetSqlBulkCopy(ds, oracleConn);
将数据全部插入到目标数据库中,启用触发器,然后通过更新临时表中的字段(doupdate)来触发。此时需要在源数据库A的视图和目标数据库B
的临时表中增加一个临时的字段(doupdate)。
禁用和启用触发器的存储过程方法如下:

create or replace procedure Trigger_OnOff(p_OnOff number) is
     cursor c is select TABLE_NAME from user_all_tables WHERE TABLE_NAME LIKE '%_TEMP';
     tablename varchar2(100);
     sqlstr varchar2(1000);
   begin
     open c;
    loop
     fetch c into tablename;
       exit when c%notfound;
         if p_OnOff=0 then --0禁用 1启用
           sqlstr:='alter table '||tablename||' disable all triggers';
        else 
          sqlstr:='alter table '||tablename||' enable all triggers';
        end if;
          execute immediate sqlstr;
       -- dbms_output.put_line(sqlstr);
     end loop;
    close c;
  end;
  

CLIENT端调用存储过程来禁用触发器
OracleCommand OracleCmd2 = new OracleCommand("TRIGGER_ONOFF", oracleConn);
OracleCmd2.CommandType = CommandType.StoredProcedure;
OracleParameter id = OracleCmd2.Parameters.Add("@b", OracleDbType.Int32);
id.Value = 0;
OracleCmd2.ExecuteNonQuery();

//调用存储过程来启用触发器
OracleCommand OracleCmd3 = new OracleCommand("TRIGGER_ONOFF", oracleConn);
OracleCmd3.CommandType = CommandType.StoredProcedure;
OracleParameter id1 = OracleCmd3.Parameters.Add("@b", OracleDbType.Int16);
id1.Value = 1;
OracleCmd3.ExecuteNonQuery();

7、CLIENT端添加定时器

private System.Timers.Timer timer1;

timer1 = new System.Timers.Timer(1000 * 60 * 2);
timer1.Elapsed += new System.Timers.ElapsedEventHandler(Timer1Action);
timer1.AutoReset = true;
timer1.Enabled = true;

public void Timer1Action(object sender, System.Timers.ElapsedEventArgs e)
{
   //事务处理方法
}

posted @ 2012-02-13 12:05  月亮的影子  阅读(1547)  评论(4编辑  收藏  举报