使用 Docker 和 Connect SE 从 Oracle 迁移数据到 MariaDB:一步一步指南

在这篇博客中,我们将学习如何将数据从 Oracle 迁移到 MariaDB。

首先,我们将学习 Oracle 数据库的基础知识,以便理解演示示例中执行的步骤。之后,我们将在 Oracle 中创建一个表并将其迁移到 MariaDB。

从 Oracle 迁移数据有两种方法

  1. 将 Oracle 数据导出为 CSV 并将其加载到 MariaDB 中。
  2. 使用 Connect 存储引擎 根据 Oracle 的源定义创建表或插入数据。

为了演示,我们将使用一个带有 Oracle Express Edition (XE) 镜像的 docker 容器。

为了简单起见,我们将在同一个容器中启动一个 MariaDB 实例并将数据迁移到其中。

我花了很多时间才使其工作,主要是因为不了解 Oracle 和 Oracle 镜像的基础知识(下面会解释)。我将简要描述读者需要了解的 Oracle 知识以便理解命令,以及未来 MariaDB 开发中可能发生的情况。

Oracle 术语

为了清楚了解将要进行哪些更改,让我们解释一下后续示例中将使用的基本术语。

SID

在 Oracle 中,SID 代表系统标识符,它是用于标识特定服务器或系统上的 Oracle 数据库实例的唯一名称。每个 Oracle 数据库实例都有一个分配给它的唯一 SID,这使得它与同一系统上的其他实例区分开来。可以使用 ORACLE_SID 环境变量检查特定的数据库实例。只有当您想使用替代方式连接到容器数据库,或在 MariaDB 中称为目录 (catalog) 时,才使用 SID。在我们的示例中,它将命名为 XE

Listener (监听器)

Listener 监听进入 Oracle 数据库的客户端连接。监听器负责接受客户端连接并将其路由到适当的 Oracle 数据库实例。默认情况下,它在端口 `1521` 上监听。更改端口和添加监听器应监听的新服务和网络地址可以在 listener.ora 文件中添加。有一个 lsnrctl 工具。

Services (服务)

服务名是用于在客户端和数据库之间建立连接的特定服务的唯一标识符。每个服务名都与位于 tnsnames.ora 文件中的连接描述符相关联,客户端使用该描述符解析托管该服务的监听器的网络地址。可以使用 tnsping 工具测试服务名。

CDB 和 PDB

Oracle 引入了多租户架构的概念,其中容器数据库 (CDB) 存储零个或多个可插拔数据库 (PDB)。每个可插拔数据库本质上是一个独立的数据库,可以独立管理,但托管在容器数据库的上下文中。在下面的示例中,我们将默认使用可插拔数据库 XEPDB1。MariaDB 目前没有此功能,但正在开发创建 目录 (catalogs) 的能力,这将类似于 CDB。

用户

有默认用户 syssystempbadmin,可以使用 ORACLE_PWD 环境变量指定的密码连接。pdbadmin 用户拥有允许其管理 PDB、创建新 PDB 以及执行与多租户架构相关的其他管理任务的权限。

Oracle 源数据

需要设置的环境是在某个版本的 Oracle 数据库镜像上启动的 docker 容器。

作为第一次尝试,我试图使用来自 oracle registry 的镜像,但经过多天的尝试,我无法让 ODBC 连接器在我的 AMD 平台上工作。

之后我找到了一个使用 Oracle docker-images 仓库的设置,它工作正常。所以让我们开始演示。

启动容器

构建镜像(这将需要时间)


$ git clone https://github.com/oracle/docker-images.git
$ cd docker-images/OracleDatabase/SingleInstance/dockerfiles
# It will take some time
$ ./buildContainerImage.sh -x -v 18.4.0 -o '--build-arg SLIMMING=false'
Build completed in 390 seconds.
$ docker images|grep oracle
REPOSITORY                          TAG         IMAGE ID       CREATED          SIZE
oracle/database                     18.4.0-xe   4a141cc0a851   10 seconds ago   6.03GB

启动基于 Express Edition (XE) 的容器(等待直到其状态为 healthy)。

$ docker run --name oracle18xe --rm -d -p 1521:1521 -p 5500:5500 -e ORACLE_PWD=oracle oracle/database:18.4.0-xe
$ docker ps --format "table {{.Status}}"
STATUS
Up About an hour (healthy)

连接到容器

该 Docker 镜像带有两个服务名 XEXEPDB1,我们可以使用它们与 Oracle 客户端连接到 CDB 和 PDB。还有一个默认的监听器端口和网络地址,客户端将使用它们连接到监听器。tnsnames.ora 文件中 XEPDB1 的示例配置。

$ cat $ORACLE_HOME/network/admin/tnsnames.ora
XEPDB1 =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 0.0.0.0)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XEPDB1)
    )
  )

listener.ora 中的监听器配置定义了监听器监听的 TCP 端口、主机和 IPC 连接。

$ cat $ORACLE_HOME/network/admin/listener.ora
LISTENER =
           (DESCRIPTION_LIST =
             (DESCRIPTION =
               (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC_FOR_XE))
               (ADDRESS = (PROTOCOL = TCP)(HOST = 0.0.0.0)(PORT = 1521))
             )
           ) 

lsnrctl 工具可用于检查 lsnrctl statuslsnrctl servicestnsping 工具可用于检查服务名,例如

$ docker exec -it oracle18xe tnsping XEPDB1
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 0.0.0.0)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XEPDB1)))
OK (0 msec)

创建 Oracle 数据

为了创建数据,我们将使用 Oracle 的 sqlplus 客户端连接,创建表并插入一些值。

从这里可以使用不同的账户和/或服务连接到数据库,有多种方式:

1. 使用 sys 用户(超级用户),需要以 sysdbasysoper 别名连接到 PDB 或服务。sysdbasysoper 是在根 (CDB) 数据库上工作的系统权限。

$ docker exec -it oracle18xe sqlplus sys/oracle@XEPDB1 as sysdba
$ docker exec -it oracle18xe sqlplus sys/oracle@XEPDB1 as sysoper
$ docker exec -it oracle18xe sqlplus sys/oracle@XE as sysdba

2. system 用户是一个没有超级用户权限的标准用户,可以使用相同的服务名。

$ docker exec -it oracle18xe sqlplus system/oracle@XE

3. pdbadmin 用户只能连接到 XEPDB1 可插拔数据库。

$ docker exec -it oracle18xe sqlplus pdbadmin/oracle@XEPDB1

了解了如何使用客户端连接后,让我们使用标准用户在可插拔数据库上创建数据。

$ docker exec -it oracle18xe sqlplus system/oracle@XEPDB1
Connected to:
Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Version 18.4.0.0.0

SQL> show con_name;
CON_NAME
------------------------------
XEPDB1
SQL> -- Use simple table
SQL> create table t(t number);
SQL> desc t;
 Name					   Null?    Type
 ----------------------------------------- -------- ----------------------------
 T						    NUMBER
SQL> insert all into t(t) values (1) into t(t) values (2) into t(t) values(3) select 1 from dual;
SQL> select * from t;

	 T
----------
	 1
	 2
	 3

太棒了!我们现在有了想要迁移到 MariaDB 的数据。

MariaDB 设置

安装 MariaDB 服务器

您可以使用不同的容器分别安装 MariaDB 和 Oracle,但由于目的是演示数据迁移的工作原理,让我们使用已创建的 Oracle 容器来容纳这两个数据库。对于网络上的容器,其原理应该是一样的。

第一步是安装 MariaDB Server,但在安装之前,我们需要一些依赖项,例如 Oracle 容器中的 epel 仓库和编辑器。

$ docker exec -it oracle18xe bash
$ yum update
$ yum install http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm vi

对于服务器,让我们选择最新的 11.0 RC 版本,使用 MariaDB Foundation repo-config 仓库。

$ cat /etc/yum.repos.d/mariadb.repo 
[mariadb]
name = MariaDB
baseurl = https://ftp.bme.hu/pub/mirrors/mariadb/yum/11.0/centos/$releasever/$basearch
module_hotfixes = 1
gpgkey = https://ftp.bme.hu/pub/mirrors/mariadb/yum/RPM-GPG-KEY-MariaDB
gpgcheck = 1
# check  yum repolist
$ yum update

准备安装 MariaDB 服务器

$ yum install MariaDB-server
$ rpm -q -a|grep -e Maria
MariaDB-common-11.0.1-1.el7.centos.x86_64
MariaDB-client-compat-11.0.1-1.el7.centos.noarch
MariaDB-server-compat-11.0.1-1.el7.centos.noarch
MariaDB-compat-11.0.1-1.el7.centos.x86_64
MariaDB-client-11.0.1-1.el7.centos.x86_64
MariaDB-server-11.0.1-1.el7.centos.x86_64

现在从这一步开始,有两种选择。

  1. 将 Oracle 数据导出为 CSV 格式,
  2. 使用 Connect SE。

对于前一种情况,我尝试过将数据导出为 CSV 格式,但 Oracle 的 XE 版本不支持此功能,我也没有尝试过企业版。我还尝试使用 expdp 工具创建导出文件,但它生成的是二进制文件,因此我不清楚如何将其用于迁移。在这种情况下,命令应该是直观的。创建 Oracle 脚本并执行它,以获取 CSV 文件。

SQL> edit dumpOracle
# Write the content
SET MARKUP CSV ON
SET HEADING OFF
SET FEEDBACK OFF
SET COLSEP ','
SET TRIMSPOOL ON
SPOOL table_oracle.csv
SELECT t FROM t;
# execute the script
SQL> @dumpOracle
SQL>  SPOOL OFF

在 MariaDB 端,您应该创建表并从文件中加载数据。

MariaDB [test]> create table t(t int);
MariaDB [test]> LOAD DATA INFILE '/table_oracle.csv'
INTO TABLE t
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES;

如果您成功完成了这一步,请在评论中告诉我。

让我们继续第二种情况,使用 Connect SE。

使用 Connect SE 将数据迁移到 MariaDB

这里将使用 Connect SE 和 ODBC。

我们需要从软件包中安装 Connect SE,安装 ODBC 驱动管理器,设置 ODBC 配置,然后进行迁移。所有步骤都应该在 Oracle 容器内部执行。

安装 Connect SE

我们需要 mariadb-connect-engine 软件包。

$ yum install MariaDB-connect-engine
$ rpm -q -a|grep -e MariaDB-connect
MariaDB-connect-engine-11.0.1-1.el7.centos.x86_64
# Check shared library
$ ls /usr/lib64/mysql/plugin/ha_connect*
ha_connect.so

ODBC 配置

要创建 ODBC 连接,我们需要 unixODBC 驱动管理器。它是 mariadb-connect-engine 软件包的依赖项,因此它已经安装。

$ rpm -q -a|grep -e ODBC
unixODBC-2.3.1-14.0.1.el7.x86_64

unixODBC 提供了诸如 isql(CLI SQL 工具)和 odbcinst(用于 ODBC 配置的 CLI)等实用工具,我们将在下面使用它们。

安装驱动管理器后,我们需要连接到 Oracle 数据库,使用 Oracle 的 ODBC 驱动程序 libsqora.so,并将其路径添加到 LD_LIBRARY_PATH

$ export LD_LIBRARY_PATH=$ORACLE_HOME/lib/

设置 ODBC 驱动程序

通过将其写入 odbcinst.ini 文件来创建 Oracle 的 ODBC 驱动程序。驱动程序的默认位置是 /etc/odbcinst.ini,您可以通过执行 odbcinst -j 来检查。

已经有 MySQL 和 PostgreSQL 的 ODBC 连接设置,因此我们需要更新它以使用 OracleODBC 配置,并通过应用 odbcinst CLI 进行检查。

# update the configuration file (no need to install)
$ cat /etc/odbcinst.ini 
[OracleODBC]
Description    = ODBC for Oracle
Driver         = /opt/oracle/product/18c/dbhomeXE/lib/libsqora.so.18.1

# query for the driver
$ odbcinst -q -d
[PostgreSQL]
[MySQL]
[OracleODBC]

设置 ODBC 数据源名称 (DSN))

我们需要添加配置以使用上一步创建的驱动程序访问 Oracle 数据库,方法是在 ~/.odbc.ini 中设置配置,就像我们连接到 Oracle 那样。该文件是用户数据源的默认文件,但由于我们在容器中使用 root 用户,因此也可以使用系统数据源 /etc/odbc.ini

$ cat ~/.odbc.ini 
[oracle]
Driver = OracleODBC
DSN = Oracle ODBC connection
ServerName = XEPDB1
UserID = system
Password = oracle

使用 odbcinst 验证您的 DSN

odbcinst -q -s
[oracle]

检查 DSN 连接

使用 isql 工具检查上面创建的名为 oracle 的 DSN

 isql -v oracle
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> select * from t;
+-----------------------------------------+
| T                                       |
+-----------------------------------------+
| 1                                       |
| 2                                       |
| 3                                       |
+-----------------------------------------+
SQLRowCount returns -1
3 rows fetched

如果这一步成功了,您距离迁移到 MariaDB 只剩一步了。

迁移

启动 MariaDB Server 并加载 Connect SE 插件

$ mariadbd --user=root --plugin-load-add=ha_connect.so &
2023-04-27 12:31:03 0 [Note] Starting MariaDB 11.0.1-MariaDB source revision 158a58245813b1959d6ee912d77734620c7cf3ba as process 1061
2023-04-27 12:31:03 0 [Note] CONNECT: Version 1.07.0002 March 22, 2021
Version: '11.0.1-MariaDB'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MariaDB Server

使用 mariadb 客户端连接,并使用 Connect SE 创建表,它将自动发现列、创建它们并加载数据。

$ mariadb -uroot test
# Migration is done here
MariaDB [test]> create table table_maria engine=connect table_type=ODBC tabname='t' Connection='DSN=oracle' SRCDEF='select * from t';
Query OK, 0 rows affected (0.059 sec)

# Check data
MariaDB [test]> select * from table_maria;
+------+
| T    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.052 sec)

MariaDB [test]> show create table table_maria \G
*************************** 1. row ***************************
       Table: table_maria
Create Table: CREATE TABLE `table_maria` (
  `T` double(40,0) DEFAULT NULL
) ENGINE=CONNECT DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci CONNECTION='DSN=oracle' `TABLE_TYPE`='ODBC' `TABNAME`='t' `SRCDEF`='select * from t'
1 row in set (0.000 sec)

就是这样!一旦建立了 ODBC 配置,将数据从 Oracle 迁移到 MariaDB 就相当轻松了。

延伸阅读

欢迎反馈

如果您在这篇博客中遇到任何问题,或者设计方面的问题,或者边缘情况不如预期,请告诉我们。欢迎您在 Zulip 上与我们交流。一如既往,您可以在 MDEV 项目中使用我们的 JIRA 提交您遇到的任何 bug/功能请求。