關於跨DB增量(增、改)同步兩張表的數據小技巧

有些場景下,須要隔離不一樣的DB,彼此DB之間不能互相訪問,但實際的業務場景又須要從A DB訪問B DB的情形,這時怎麼辦?我認爲有以下常規的三種方案:html

1.雙方提供RESET API,須要訪問不一樣DB數據時,能夠經過API來獲取指定數據;sql

這種方案優勢是隔離性、定製性強,統一出入口,只能經過指定的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表中。ui

這種方案的優勢是:能夠根據實際狀況靈活定製同步的表數據,不侷限於某一張表或某一個DB,能夠保證不一樣DB間同步表的數據一致性,讓原本跨DB操做表變成了同一個DB的事情,並且能夠增、刪、改、查,功能不受限;缺點是靈活性太強,程序代碼實現可靠的跨DB的實時同步邏輯的實現複雜度較高,對於開發人員的要求較高,若是寫的同步邏輯沒法保證明時、可靠、高可用,那對於業務來說是災難性的。日誌

上述三種方案,第一、2方案基本都是定製化的常規方案,我(夢在旅途,http://www.zuowenjun.cn)今天要分享的是第3種方案:跨DB增量(增、改)同步兩張表的數據,注意是增量同步,其中刪除這個我沒有說明,緣由是若是DB表中記錄是物理刪除(即:真實的DELETE),那就沒法簡單的經過程序代碼獲取到刪除的記錄,除非在DB中加入DELETE觸發器記錄刪除記錄的主鍵到臨時表或開啓更改追蹤(CHANGE_TRACKING)或DB日誌分析,故本文講的是不給表、DB增長額外負擔的狀況實時增量同步,至於刪的同步這個我認爲最好是邏輯標記刪除(過時最後清理【真實刪除】),而不要物理刪除。orm

關於程序代碼實現跨DB同步表數據方案,以前已有總結過,詳見:https://www.cnblogs.com/zuowj/p/6264711.html  ---》4.利用BCP(sqlbulkcopy)來實現兩個不一樣數據庫之間進行數據差別傳輸(即:數據同步)htm

 以前的文章同步主要是基於TranFlag標記字段 或觸發器來實現同步,這種方式必需對錶數據的增、刪、改邏輯都有要求與規範,也就是增、改必需更改TranFlag=0,刪必需記錄表刪除臨進表中,這樣才能實現同步邏輯,而今天是在這個同步基礎上(BCP),不給表、DB增長額外負擔的狀況實時增量同步,對數據源的插入、改動沒有要求。blog

代碼以下:(如下同步適用於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有問題,致使一直同不不成功,可能會出現一直同步不過去的狀況,這種狀況能夠加上預警+人工干預,這個是機率的事情。

好了,若是你們有什麼好的意見或建議歡迎下方留言評論,謝謝!

相關文章
相關標籤/搜索