您的位置:首页 > 数据库 > Oracle

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

2012-02-13 12:05 295 查看
问题描述:数据库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)
{
//事务处理方法
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: