如何实时将Oracle单表选中列同步插入并更新至另一Oracle库的表
可行性结论
完全可以通过Shell脚本实现该需求,核心依赖Oracle官方的sqlplus命令行工具完成跨库数据读写,搭配轮询逻辑即可实现监听、新增、变更同步的全流程。
具体实现方案
前置准备
- 运行脚本的服务器需安装Oracle Instant Client及
sqlplus工具,确保能正常连接XYZ和MNO两个数据库 - 为两个数据库分配对应权限的账号:XYZ库账号需具备表A的查询权限,MNO库账号需具备表B的INSERT、UPDATE权限
- 确认表A和表B有一致的主键/唯一键字段,用于变更场景下的行匹配
核心逻辑设计
- 轮询机制
通过Shell死循环(适合低延迟需求)或crontab定时任务(适合分钟级延迟需求),按业务可接受的间隔执行查询操作 - 增量过滤
推荐两种方式避免重复拉取全量数据:- 方案1:在表A新增
同步状态和最后更新时间字段,每次查询带where条件WHERE 同步状态 = '未同步' OR 最后更新时间 > 上次同步时间,同步完成后更新对应行的同步状态和同步时间 - 方案2:本地维护一个日志文件记录上次同步的最大主键值和最大更新时间,每次查询只拉取主键大于记录值、或更新时间大于记录时间的行
- 方案1:在表A新增
- 数据写入
直接使用Oracle的MERGE INTO语法,一次性完成新增行插入、变更行更新的操作,不需要分开写INSERT和UPDATE逻辑,保证原子性
示例Shell脚本
#!/bin/bash # 数据库连接配置 XYZ_CONN="用户名/密码@XYZ库IP:端口/服务名" MNO_CONN="用户名/密码@MNO库IP:端口/服务名" LOG_FILE="./sync_log.log" LAST_SYNC_TIME="./last_sync.time" # 初始化上次同步时间 if [ ! -f $LAST_SYNC_TIME ]; then echo "2020-01-01 00:00:00" > $LAST_SYNC_TIME fi LAST_TIME=$(cat $LAST_SYNC_TIME) CURRENT_TIME=$(date "+%Y-%m-%d %H:%M:%S") # 从XYZ库查询增量数据,导出为临时sql文件 sqlplus -S $XYZ_CONN << EOF > ./merge_data.tmp SET HEADING OFF SET FEEDBACK OFF SET LINESIZE 1000 SELECT 'MERGE INTO 表B b USING (SELECT '''||主键字段||''' AS pk, '''||字段1||''' AS col1, '''||字段2||''' AS col2 FROM DUAL) a ON (b.主键字段 = a.pk) WHEN MATCHED THEN UPDATE SET b.字段1 = a.col1, b.字段2 = a.col2 WHEN NOT MATCHED THEN INSERT (主键字段, 字段1, 字段2) VALUES (a.pk, a.col1, a.col2);' FROM 表A WHERE 你的自定义where条件 AND 最后更新时间 > TO_DATE('$LAST_TIME', 'yyyy-mm-dd hh24:mi:ss'); EXIT; EOF # 执行同步操作到MNO库 if [ -s ./merge_data.tmp ]; then sqlplus -S $MNO_CONN << EOF SET HEADING OFF SET FEEDBACK OFF @./merge_data.tmp COMMIT; EXIT; EOF echo "[$CURRENT_TIME] 同步完成,更新同步时间" >> $LOG_FILE echo $CURRENT_TIME > $LAST_SYNC_TIME else echo "[$CURRENT_TIME] 无增量数据" >> $LOG_FILE fi # 清理临时文件 rm -f ./merge_data.tmp
注意事项
- 脚本中的字段名、where条件、日期格式需要根据实际业务场景调整,字符串类型字段要做好转义避免sql语法错误
- 生产环境建议增加异常捕获逻辑,
sqlplus执行报错时要记录错误日志,不要直接更新同步时间,避免漏同步 - 如果对同步延迟要求在秒级以内,不建议使用Shell轮询方案,可改用Oracle CDC、物化视图日志、触发器等数据库原生能力实现
内容的提问来源于stack exchange,提问作者Sneha
相关产品推荐
相关产品推荐

