在数据库同步中我们经常会用到DBLink方式。DBLink可以将物理上存放于网络的多个数据库在逻辑上当成一个单一的大数据库。开发人员无需关心数据库的网络分布,就能很方便的实现从不同数据库之间读取数据。如何在Oracle数据库间建立DBLink我在之前的文章已有涉及,这里就不花篇幅讲解了。具体请查看Oracle建立DBLink。
本篇文章主要阐述如何解决DBLink方式无法实现Blob、Clob字段数据同步的问题。在网上已经有很多牛人给出了解决方案,在参照他们的方案解决问题的过程中,发现有些小问题并没有解决,而且也没有人给出一个完整的解决过程。这里我把我的解决过程记录下来,供大家参考。
首先,我们看一下DBLink为何不能实现Blob、Clob字段的同步。我在我本机Oracle数据库中建立了DEVD数据库的Database Link。当我们Select没有大字段的DEVD数据库的表的时候,数据能查询出来。当我们查找含有大字段的表时,系统给出如下提示:
select * from JJR_TJJR_CYZGXX@DEVDBLINKJJR_TJJR_CYZGXX表中还有Blob字段。
因为Oracle不允许LOB属性的数据进行DBLink方式的查询的。解决此类问题有人提出使用临时表的形式进行中转,然后再进行数据的同步。使用这种方法确实能够解决问题,具体解决方案如下:
1.使用子查询来建立临时表,实现本地临时表复制远程数据库表的数据。
Create global temporary table temp on commit preserve rows as select * from JJR_TJJR_CYZGXX@DEVDBLINK为什么要用On commit preserve rows, 我之前的Oracle用子查询创建临时表的问题总结中已经提到。
通过查询temp表,我们发现所有JJR_TJJR_CYZGXX表中的数据已经同步到temp表中。
2.在本地test表中同步临时表temp的数据,先删除test表中数据,然后用子查询实现数据复制。
Insert into test select * from temp通过查询本地test表,我们看到即使含有Blob字段的表的数据已经查询过来。
其他解决方案:
通过临时表能够实现含大字段表的数据同步,我们之间使用本地表是否也能达到相同的效果呢?通过实验我们发现直接通过本地表也是能够实现的。
首先建立test1表,结构和JJR_TJJR_CYZGXX表结构一致。通过子查询来实现数据复制
Insert into test1 select * from JJR_TJJR_CYZGXX@DEVDBLINK通过查询test1表我们发现数据已经复制。
--创建临时表: create global temporary table lob2 ( line number primary key, text clob ) on commit delete rows; --插入数据: SQL> insert into lob2 select line,text from lob1@lob_link; 499 rows created. SQL> select * from lob2 where rownum<5; LINE TEXT ---------- --------------------------------------------------------------------- 5 8 type NUMBER is NUMBER_BASE; 9 subtype FLOAT is NUMBER; -- NUMBER(126) 11 subtype "DOUBLE PRECISION" is FLOAT; SQL> commit; Commit complete. SQL> select * from lob2 where rownum<5; no rows selected --提交之后数据就被删除了,这个是临时表的属性。