在企业级数据管理中,经常需要实现不同数据库系统之间的数据同步。Oracle和MySQL作为两种主流的关系型数据库,它们的异构性给数据同步带来了挑战。本文将详细介绍如何使用Oracle的DB_Link功能实现与MySQL数据库的数据同步。
这种方案特别适合以下场景:
Oracle通过DG4ODBC驱动实现与MySQL的连接。首先需要确认驱动是否已安装:
bash复制$ file $ORACLE_HOME/bin/dg4odbc
如果驱动不存在,需要从Oracle官网下载并安装对应的ODBC驱动。安装完成后,建议设置环境变量:
bash复制export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/local/lib:$LD_LIBRARY_PATH
创建odbc.ini配置文件,这是连接MySQL的关键:
ini复制$ vi $ORACLE_BASE/odbc.ini
[myodbc5]
Driver = /home/dbs/app/myodbc-x.x.x/lib/libmyodbc5.so
Description = Connector/ODBC x.x Driver DSN
SERVER = <MySQL服务器IP>
PORT = <MySQL端口>
USER = mysql_user
PASSWORD = *****
DATABASE = test
OPTION = 0
TRACE = OFF
注意事项:
配置tnsnames.ora文件:
bash复制$ vi $ORACLE_HOME/network/admin/tnsnames.ora
myodbc5 =
(DESCRIPTION=
(ADDRESS=(PROTOCOL=TCP)(HOST=[MySQL主机])(PORT=1521))
(CONNECT_DATA=(SID=myodbc5))
(HS=OK)
)
配置listener.ora文件:
bash复制$ vi $ORACLE_HOME/network/admin/listener.ora
SID_LIST_LISTENER=
(SID_LIST=
(SID_DESC=
(SID_NAME=myodbc5)
(ORACLE_HOME=/home/dbs/app/Ora/product/11.2.0/dbhome_1)
(PROGRAM=dg4odbc)
(ENV="LD_LIBRARY_PATH=/home/dbs/app/unixodbc-2.2.14/lib:/home/dbs/app/Ora/product/11.2.0/dbhome_1/lib")
)
)
配置完成后重新加载监听:
bash复制$ lsnrctl reload
创建initmyodbc5.ora文件:
bash复制$ vi $ORACLE_HOME/hs/admin/initmyodbc5.ora
HS_FDS_CONNECT_INFO=myodbc5
HS_FDS_TRACE_LEVEL=OFF
HS_FDS_SHAREABLE_NAME=/home/dbs/app/unixodbc-2.3/lib/libodbc.so
HS_FDS_SUPPORT_STATISTICS=FALSE
HS_LANGUAGE=AMERICAN_AMERICA.AL32UTF8
set ODBCINI=/home/dbs/etc/odbc.ini
关键参数说明:
在Oracle中创建DB_Link:
sql复制CREATE PUBLIC DATABASE LINK OM_LINK
CONNECT TO "mysql_user" IDENTIFIED BY "password"
USING 'myodbc5';
测试连接:
sql复制SELECT * FROM "test_table"@OM_LINK;
在Oracle中创建目标表:
sql复制CREATE TABLE test_t1(
id NUMBER PRIMARY KEY,
create_date DATE
);
创建同步控制表:
sql复制CREATE TABLE om_sync_control (
table_name VARCHAR2(50) PRIMARY KEY,
last_sync_id NUMBER(18),
last_sync_time DATE,
sync_status VARCHAR2(10)
);
创建错误日志表:
sql复制CREATE TABLE om_sync_error_log (
table_name VARCHAR2(50),
ids NUMBER(20),
om_error VARCHAR2(4000),
insert_date DATE
);
sql复制CREATE OR REPLACE PROCEDURE SYNC_ON_INCREMENTAL IS
v_max_id NUMBER := 0;
v_count NUMBER := 0;
v_last_sync_id NUMBER;
v_sync_time DATE := SYSDATE;
CURSOR new_data_cur IS
SELECT id, create_date
FROM test_t1@OM_LINK
WHERE id > (SELECT NVL(last_sync_id, 0)
FROM om_sync_control
WHERE table_name = 'test_t1')
ORDER BY id;
BEGIN
-- 获取上次同步ID并加锁
SELECT NVL(last_sync_id, 0)
INTO v_last_sync_id
FROM om_sync_control
WHERE table_name = 'test_t1'
FOR UPDATE;
-- 处理新增数据
FOR rec IN new_data_cur LOOP
BEGIN
INSERT INTO test_t1 VALUES(rec.id, rec.create_date);
IF rec.id > v_max_id THEN
v_max_id := rec.id;
END IF;
v_count := v_count + 1;
-- 每100条提交一次
IF MOD(v_count, 100) = 0 THEN
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
INSERT INTO om_sync_error_log
VALUES('test_t1', rec.id, SQLERRM, SYSDATE);
COMMIT;
END;
END LOOP;
-- 更新同步状态
IF v_max_id > 0 THEN
UPDATE om_sync_control
SET last_sync_id = v_max_id,
last_sync_time = v_sync_time,
sync_status = 'SUCCESS'
WHERE table_name = 'test_t1';
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
UPDATE om_sync_control
SET sync_status = 'FAILED',
last_sync_time = SYSDATE
WHERE table_name = 'test_t1';
COMMIT;
RAISE;
END SYNC_ON_INCREMENTAL;
创建定时任务:
sql复制BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name=>'SYNC_JOB_HOURLY',
job_type => 'STORED_PROCEDURE',
job_action=>'SYNC_ON_INCREMENTAL',
start_date => SYSDATE,
repeat_interval=>'FREQ=HOURLY;INTERVAL=1',
enabled=>TRUE
);
END;
查看任务执行状态:
sql复制SELECT * FROM DBA_SCHEDULER_JOBS
WHERE job_name ='SYNC_JOB_HOURLY';
查看执行详情:
sql复制SELECT * FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name ='SYNC_JOB_HOURLY'
ORDER BY log_date DESC;
sql复制-- 原代码
IF MOD(v_count, 100) = 0 THEN
COMMIT;
END IF;
-- 优化建议:根据数据量调整提交频率
IF v_count > 0 AND (MOD(v_count, 500) = 0 OR v_count = 1) THEN
COMMIT;
END IF;
sql复制-- 在MySQL源表上确保id字段有索引
CREATE INDEX idx_test_t1_id ON test_t1(id);
-- 在Oracle目标表上也创建相应索引
CREATE INDEX idx_oracle_test_t1_id ON test_t1(id);
错误现象:ORA-28545: 连接代理时出错
解决方案:
bash复制lsnrctl status
bash复制isql -v myodbc5 mysql_user password
bash复制telnet <MySQL_IP> <MySQL_PORT>
错误现象:中文乱码或数据截断
解决方案:
sql复制-- Oracle端
SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER LIKE '%CHARACTERSET%';
-- MySQL端
SHOW VARIABLES LIKE 'character_set%';
ini复制HS_LANGUAGE=AMERICAN_AMERICA.AL32UTF8
错误现象:同步速度慢
优化建议:
对于需要同步多个表的情况,可以改造存储过程:
sql复制CREATE OR REPLACE PROCEDURE SYNC_MULTI_TABLES IS
TYPE table_list IS TABLE OF VARCHAR2(50);
tables table_list := table_list('table1', 'table2', 'table3');
BEGIN
FOR i IN 1..tables.COUNT LOOP
-- 动态SQL处理每个表
EXECUTE IMMEDIATE 'BEGIN SYNC_SINGLE_TABLE(''' || tables(i) || '''); END;';
END LOOP;
END;
实现Oracle和MySQL双向同步的架构:
对于大数据量表:
优点:
缺点:
优点:
缺点:
MySQL主从复制+Oracle GoldenGate:
sql复制-- MySQL端只授予必要权限
GRANT SELECT ON test.test_t1 TO 'mysql_user'@'%';
测试环境验证:在生产环境实施前,务必在测试环境充分验证
监控方案:实现完善的监控,包括:
文档记录:详细记录:
备份策略:确保有完整的备份和恢复方案
性能基准测试:在不同数据量下测试同步性能,确定最佳批量大小和频率