关于跨DB增量(增、改)同步两张表的数据小技巧
有些场景下,需要隔离不同的DB,彼此DB之间不能互相访问,但实际的业务场景又需要从A DB访问B DB的情形,这时怎么办?我认为有如下常规的三种方案:
1.双方提供RESET API,需要访问不同DB数据时,可以通过API来获取指定数据;
这种方案优点是隔离性、定制性强,统一出入口,只能通过指定的API访问指定的数据;缺点与优点是对立的,也就是定制性太强,导致每次业务发生变更,需要访问不同数据的时候,需要双方更改API的入参或返参,降低了开发效率;而且无法使用表JOIN,这样在某些情况下也会导致查询数据效率变低。目前主流的方案都是建议使用API方案
2.利用DB的同步技术(如:SQL SERVER的订阅复制、MYSQL的主从复制脚本等)来实现不同DB的数据同步共享
这种方案优点是可以在同一个DB访问到另一个DB中所需表的数据,可以直接JOIN,把原来的跨DB访问变成了同一个DB的事情;缺点是依赖DB的同步技术,而且两台DB服务器的网络必需互通,没有完全的隔离,且往往同步过来的表不允许直接修改,或需修改仍然需要跨DB修改或使用方案1的API来进行修改。
3.通过程序代码实现两个DB的数据同步(增、删、改、查),如:可以定时轮询源DB的A表,然后获取变更的记录(一般是:增、删、改的记录),再通过程序代码把源DB的A表的变更记录批量更新(若是新增、则是插入,若是修改,则是更新,若是删除,则是删除)到目的DB的A表中。
这种方案的优点是:可以根据实际情况灵活定制同步的表数据,不局限于某一张表或某一个DB,可以保证不同DB间同步表的数据一致性,让本来跨DB操作表变成了同一个DB的事情,而且可以增、删、改、查,功能不受限;缺点是灵活性太强,程序代码实现可靠的跨DB的实时同步逻辑的实现复杂度较高,对于开发人员的要求较高,如果写的同步逻辑无法保证实时、可靠、高可用,那对于业务来讲是灾难性的。
上述三种方案,第1、2方案基本都是定制化的常规方案,我(梦在旅途,http://www.zuowenjun.cn)今天要分享的是第3种方案:跨DB增量(增、改)同步两张表的数据,注意是增量同步,其中删除这个我没有说明,原因是如果DB表中记录是物理删除(即:真实的DELETE),那就无法简单的通过程序代码获取到删除的记录,除非在DB中加入DELETE触发器记录删除记录的主键到临时表或开启更改追踪(CHANGE_TRACKING)或DB日志分析,故本文讲的是不给表、DB增加额外负担的情况实时增量同步,至于删的同步这个我认为最好是逻辑标记删除(过期最后清理【真实删除】),而不要物理删除。
关于程序代码实现跨DB同步表数据方案,之前已有总结过,详见:https://www.cnblogs.com/zuowj/p/6264711.html ---》4.利用BCP(sqlbulkcopy)来实现两个不同数据库之间进行数据差异传输(即:数据同步)
之前的文章同步主要是基于TranFlag标记字段 或触发器来实现同步,这种方式必需对表数据的增、删、改逻辑都有要求与规范,也就是增、改必需更改TranFlag=0,删必需记录表删除临进表中,这样才能实现同步逻辑,而今天是在这个同步基础上(BCP),不给表、DB增加额外负担的情况实时增量同步,对数据源的插入、改动没有要求。
代码如下:(以下同步适用于SQL SERVER 不同DB的表增量同步)
try
{
SqlConnection obConnSrc = new SqlConnection(connLMSStr);
SqlConnection obConnDest = new SqlConnection(mconnCCSStr); string lastTamp = ClsDatabase.gGetFieldValue(obConnSrc, "update TS_SyncUptime set UPTime=GETDATE() OUTPUT (deleted.LastUPstamp) as oldtamp FROM TS_CCSUptime WHERE TableName=N'tableNameA'", "oldtamp"); string selectSql = @"SELECT id,aaa,bbb,ccc,ddd,eee,fff
FROM tableNameA WHERE 其它同步过滤查询条件 AND CONVERT(bigint,sys_tamp)>{0}"; selectSql = string.Format(selectSql, lastTamp); master.TransferBulkCopy(selectSql, obConnSrc,
"tableNameA", obConnDest,
(stable) =>
{
var colMaps = new Dictionary<string, string>();
foreach (DataColumn col in stable.Columns)
{
colMaps.Add(col.ColumnName, col.ColumnName);
}
return colMaps;
},
(tempTableName, stable, destConn, srcConn) =>
{
StringBuilder saveSqlBuilder = new StringBuilder("begin tran" + Environment.NewLine); string IUSql = master.BuildInsertOrUpdateToDestTableSql("tableNameA", tempTableName, new[] { "id" }, stable.ExtendedProperties[master.MapDestColNames_String], 2);
saveSqlBuilder.Append(IUSql); saveSqlBuilder.AppendLine("commit"); ClsDatabase.gExecCommand(destConn, saveSqlBuilder.ToString()); ClsDatabase.gExecCommand(srcConn, "update TS_SyncUptime set UPTime=GETDATE(),LastUPstamp=CONVERT(bigint,sys_tamp) FROM TS_SyncUptime WHERE TableName=N'tableNameA'"); return false;
}); }
catch (Exception ex)
{
writeLog(ex);//记错误日志
}
上述同步代码逻辑很简单,可以参照之前的文章,这里主要是说明几个重要点:
1.TS_SyncUptime表用于记录与管理同步任务的信息,主要包含如下几个字段:
TableName:要同步的表名,UPTime每一次同步的触发时间点(可更改),sys_tamp行变更时间戳(不可更改),LastUPstamp行最后有效变量时间戳(可以更新)
2.具体关键同步逻辑如下:
2.1先更新TS_SyncUptime表,以便触发sys_tamp行变更时间戳发生改变(相当于记录同步触发时间点),在更改的同时取出LastUPstamp行最后有效变更时间戳(相当于上次同步的触发时间点)
2.2使用LastUPstamp作为过滤条件,查询>源DB的源表中时间戳字段,这样就可以查询出自上一次同步触发点到当前时间待同步的记录(增、改)
2.3利作BCP执行同步(详见之前文章说明)
2.4确保同步成功后,再次更新TS_SyncUptime表,并把sys_tamp行变更时间戳(当前触发时间点)更新到LastUPstamp行最后有效变量时间戳(记住本次触发时间点)
如上步骤即可实现可靠的同步,有人可能有疑问,这样就能实现可靠同步吗?我这里解释一下:
3.1同步触发时记录当前触发时间点,并取得上一次的触发时间点(这里的上一次触发时间点是指上一次开始准备同步的记录时间点,确保从上一次查询到同步完成之间的时间点都包括其中,防止漏数据)
3.2如果同步的任一环节失败(只要最终没有同步成功),那么再次同步触发时均取到的是同 一个时间点(LastUPstamp),而且即使重复执行同步逻辑,也不会出现重复(因为存在则更新不存在则插入原则),保证幂等,这样就确保了同步的可靠性
3.3当然如果某个时间点的数据或某个DB有问题,导致一直同不不成功,可能会出现一直同步不过去的情况,这种情况可以加上预警+人工干预,这个是概率的事情。
好了,如果大家有什么好的意见或建议欢迎下方留言评论,谢谢!
关于跨DB增量(增、改)同步两张表的数据小技巧的更多相关文章
- Oracle:同步两张表的相同字段
有一个需求需要同步两张表的相同字段,比如表A和表B,这两张表是不同的用户下的表,表结构是一样的. 一开始我简单写了一个sql语句,如下: update ord_log1 A set (A.pid, A ...
- django同时查询两张表的数据,合并检索对象返回
原始需求: 1.一篇文章内容分N个版块,每篇文章的版块数量不同. 2.有个文章搜索功能,需要同时搜索标题和内容. 实现思路: 1.由于每篇文章的内容版块数量不同,因此将每个文章的标题和内容分开存入2张 ...
- 利用pymysql同时修改两张表的数据
使用pymysql操作数据库中相关联的两张表需求:两张表中分别有一个字段是json格式,需要往json中再插入一个属性值’container_cloud’=’fasle’. import pymysq ...
- 【第十五篇】easyui datagrid的列编辑,同时插入两张表的数据进去
看图说话. 需求:插入两张表,上面的表单是第一张表的内容,下面的两个表格是第二张详情表的内容,跟第一张表的id关联 第二张表有一个列是需要用户手动填写添加的. 国际惯例,上代码 <div id= ...
- JS之document例题讲解1(两张表之间数据转移、日期时间选择、子菜单下拉、用div做下拉菜单、事件总结)
作业一:两个列表之间数据从一个列表移动到另一个列表 <div style="width:600px; height:500px; margin-top:20px"> & ...
- mysql 两张表的数据设置主外健关联删除
image_group 主表 image 副表 alter table image add constraint fk_group_idforeign key (group_id)references ...
- 6.10---mybatis中两张表查询数据dao层
- Oracle将两张表的数据插入第三张表且第三张表中不存在
1.由于是先查再插所以不能使用insert into table1() values(), 要使用insert into table1() select * table2,不能使用values. 2. ...
- KETTLE多表关联的同步一张表的两种实现方式
以下操作都在5.0.1版本下进行开发,其余版本可以进行自动比对 在平时工作当中,会遇到这种情况,而且很常见.比如:读取对方的多个视图或者表,写入目标库的一张表中,就涉及到多表的同步. 多表同步可以有以 ...
随机推荐
- javascript中的函数节流和函数去抖
带着问题去尝试 首先我们要知道为什么要用到函数节流和函数去抖?我们带着以下的疑问来进行分析! 1.比如搜索框,你会用到什么事件(change.blur.keyup等)?去做什么效果?2.再比如scro ...
- webpack2入门概念
webpack是一种JavaScript应用模块化打包工具,它配置起来简单易上手,因此很多企业工程化代码都使用它来打包.在具体介绍如何使用webpack之前,先来介绍下webpack的四个核心概念. ...
- R语言读入数据库的中英名词互译测试并计分脚本(考试用)
1. 分子生物学中英文.csv,输入文件,两列,以tab键分隔的txt文本,没有列名 2. 错误的名解.csv, 如果在测试中拼写错误,会写出到这个文件,可用这个容易犯错的名词进行新的测试 3. 注意 ...
- MySql操作(一)
1.连接Mysql 格式: mysql -h主机地址 -u用户名 -p用户密码 1.连接到本机上的MYSQL.首先打开DOS窗口,然后进入目录mysql\bin,再键入命令mysql -u root ...
- 干掉safedog命令
sc delete safedogguardcenter shutdown -r -t 00 两条命令搞定
- android中进度条的实现
布局: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:androi ...
- Golang Go Go Go part1:安装及运行
golang 知识图谱 https://www.processon.com/view/link/5a9ba4c8e4b0a9d22eb3bdf0 一.安装 最新版本安装包地址:https://gola ...
- Json----简单介绍
Json 先分享一个网站http://www.bejson.com/,这个是用来检测Json文件的错误的,Json文件一般不好查找错误. 看懂Json只需要四句话: 对象表示为键值对 数据由逗号分隔 ...
- PTA第四次作业
题目 7-1 计算职工工资 1.设计思路 (1)第一步:观察题意了解各个参数与所需函数在题目中的意义: 第二步:设计算法编写函数,让函数的功能实现题目中所需的功能: 第三步:运行程序检测是否错误. ( ...
- Axure环境安装,组件引入,使用示例
资源下载: Axure的中文官方下载地址:https://www.axure.com.cn/3510/ Axure汉化包:https://www.axure.com.cn/2616/ Axure元件库 ...