几种从Oracle数据库或其它如文本文件、MariaDB (or MySQL for that matter)获取数据的方法。Oracle数据库可不愿意你这样做,因此需要做一些必要的调整。其中一种方式就是使用触发器,UDF, UPD-communication 和简单的服务器,这是 从Oracle到MariaDB的同步复制方式系列文章***部分。也就是说从Oracle导出数据到文本文件是Oracle所不愿意看到的。它希望你把数据保存在它里面,围绕它开展工作,现在你可以使用Oracle dump工具。这已经很好了且能正常处理大多数Oracle的数据类型。
对于复制,如果不使用触发器或其它机制,那么使用开源的东西可能是比较好的了,或者可以不使用说明特殊工具来做吗?一种方式是在Oracle的前面放一个代理。这非常有用,但是需要花费太多时间来开发并且要熟悉Oracle的通讯协议,可我不愿意这样做(我承认我很懒)。
因此现在我只能尝试其他方式来直接从Oracle复制数据。在后面我将演示一个实际的例子来做此事,不需要太多代码,但现在我先解释它是如何工作的。更为困难是如果正确的得到Oracle中的数据,所以这一系列博客的***部分将更多的对Oracle进行相关说明,这是一个好理由(比如:得到可用的而不必自己实现) ,让我们开始吧。
现在开始,Oracle中没有 二进制日志(binlog) (也没有修改日志)。Oracle有重做日志 ,InnoDB/XtraDB 也是使用的这种方式,它们都是基于同样的目的 —在崩溃发生时能恢复数据库。 由于重做日志要达成此目的,因此它记录了比binlog更低层次日志。数据库中任何修改事件都能够从Oracle的重做日志中找到,包括很多Oracle的内部处理。Oracle在后台做了很多东西,与MariaDB强烈依赖操作系统不同它会会更多使用自己的内部管理,比如文件空间管理等类似的东西。 当然这并不是说在这一方面Oracle比MariaDB更好,或与此相反,Oracle诞生的年代你不得不支持多种不同的操作系统,因此在在某些方面就需要设计得透明的(即设计得更抽象,高层次不必依赖操作系统实现)。同时Oracle诞生的年代多数磁盘大小仅为5MB,因此很多都是一些保守做法 (这暴露了我的年龄,是的,我的出生日期早于Mille Small主打歌曲 "My Boy Lollipop"。 与流行的看法相反,它不是Rod Stewart使用口琴独奏的那首。 ,结束了今天的“无用的知识”课).
在我们进入详细查看Oracle重做日志之前,我想先解释一些东西。在Oracle中还有另外一个文件,它很小但是却很重要,叫着控制文件。控制文件用于跟踪记录其它所有文件和关联的数据库设置。对于重做日志,有两个用途。一个基础方式是 非归档(NOARCHIVELOG)模式,意味着日志文件会被重用。这和InnoDB/XtraDB的日志文件使用方式相似,它目的也是提供一种手段来进行崩溃后恢复。想象一下,需要使用这些日志文件进行某一个时间点的恢复,前提是你保存了这些文件,比如:进行了物理备份且保存了这些文件。对于MariaDB,我们会使用binlog进行时间点的恢复。
使用重做日志的目的就是可以对Oracle进行时间点的恢复,我们不得不保存重做日志,在归档模式下Oracle有一个单独的进程"archive"来做,也就是当日志写满切换日志时把日志保存在其它地方。所有这一切,当前的和归档的重置日志文件都被记录在Oracle的控制文件中。
这些Oracle知识对于理解代码如何工作是非常重要的。还有一个我需要简要的讨论一下,就是Oracle的ROWID。ROWID 是Oracle中表的数据行的唯一标识。ROWID实际上是一个物理地址。在某些情况下,当表属于聚集表时相同的ROWID可用于两个不同的表,但是对一个表来说,里面的ROWID是唯一标识了一行。 使用表的ROWID,可以使用伪列ROWID,它可以用在WHERE和SELECT语句中。
因此,现在我们要灵活运用上面这些知识。Oracle的重做日志包含了数据库的变化,因此我们可以使用重做日志来达成MariaDB中binlog相同的目的,如:复制。为了做复制,我们首先需要能够读取重做日志,我们可以读取重做日志文件,但却相当复杂,如果你坚持这样做,你可以阅读 这个文档 中的例子,但我认为这不是一个好主意。相反,我们应该使用Oracle的工具。对于我们感兴趣的DML,我们需要复制处理表的INSERT, UPDATE和DELETE语句,然后在在事务的结束处提交。对于这些操作,我们希望重做日志中包含如下这些数据:
- 操作类型
- 表的唯一标识 (不是表名)
- 列和值的变化
- 行的ROWID
- SCN (系统变更号).
现在我需要说一说SCN。SCN非常简单;它是一个48位整型数标记了一个事务,每开始一个新事务它就向上增加。你可以获取表中***更改的SCN,实际上是row所在块的SCN(你可以跟踪ROW的变化。有很多奇奇怪怪的选项来满足用户的需求。)。
在我写完这篇博文之前,我想演示下怎么从重做日志文件获取数据的代码。在你询问之前,oracle没有重做日志单元,或类似这样的工具。这不是MariaDB,这是Oracle数据库。Oracle数据库的工具本身几乎不是工具,而是 Oracle PL/SQL包。在此例子中是日志分析,或者是一个类似DBMS_LOGMNR包。想要日志分析工作,我们需要在归档模式下运行数据库。所以如果你新安装了Oracle数据库,请以特权用户进行登录:
- $ sqlplus / as sysdba
然后运行以下命令:
- SQL> SHUTDOWN IMMEDIATE;
- SQL> STARTUP MOUNT;
- SQL> ALTER DATABASE ARCHIVELOG;
- SQL> ALTER DATABASE OPEN;
此外,为了从日志分析中获得所有数据,我们必须在重做日志中加入"supplemental data"。这意味着我还没有看其中的数据,但是如果你想看数据请相信我。在同个 SQL*Plus窗口,运行:
- SQL> ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
我们可以在此开始分析日志。这包含两个步骤:***,开始分析日志本身,然后选择一张表存储分析日志。让我们看下怎样用SQL脚本开始分析日志。调用脚本startlog.sql:
- column min_scn new_value startscn
- column current_scn new_value endscn
- SELECT MIN(FIRST_CHANGE#) min_scn FROM v$log;
- SELECT current_scn FROM v$database;
- EXECUTE DBMS_LOGMNR.START_LOGMNR(STARTSCN => &startscn, -
- ENDSCN => &endscn, -
- OPTIONS => DBMS_LOGMNR.COMMITTED_DATA_ONLY + -
- DBMS_LOGMNR.CONTINUOUS_MINE + -
- DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);
- SET ARRAYSIZE 1
然后运行脚本,因为脚本里不含明显的退出语句,所以脚本执行后还是会看到SQL*Plus的命令提示符。这和 MariaDB命令行工作方式是不同的。
- $ sqlplus / as sysdba @startlog.sql
现在我们可以获取一下日志数据,比方说我们有张表称为T1,并且已经在T1上做了些改动,那我们可以用如下语句获取相关记录:
- SQL> SELECT sql_redo FROM v$logmnr_contents WHERE table_name = 'T1' AND seg_owner = 'ANDERS' AND operation IN ('INSERT', 'UPDATE', 'DELETE');
- SQL_REDO
- --------------------------------------------------------------------------------
- insert into "ANDERS"."T1"("C1","C2") values ('1','2');
- insert into "ANDERS"."T1"("C1","C2") values ('2','2');
- update "ANDERS"."T1" set "C2" = '3' where "C2" = '2' and ROWID = 'AAAE5KAAEAAAAFfAAA';
- update "ANDERS"."T1" set "C2" = '3' where "C2" = '2' and ROWID = 'AAAE5KAAEAAAAFfAAB';
这似乎不完整!但里面的有些内容可能是有意义的,对么?有关此系列的下篇博文我们会进行尝试。这篇博文或多或少都是关于Oracle数据库的,在下篇博文中将更多描述有关复制到MariaDB的内容,MariaDB也是我们想让数据存储的地方,不是么?
快乐的SQL编程吧!