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

来源:https://www.cnblogs.com/zuowj/archive/2018/08/14/9473984.html
-Advertisement-
Play Games

有些場景下,需要隔離不同的DB,彼此DB之間不能互相訪問,但實際的業務場景又需要從A DB訪問B DB的情形,這時怎麼辦?我認為有如下常規的三種方案: 1.雙方提供RESET API,需要訪問不同DB數據時,可以通過API來獲取指定數據; 這種方案優點是隔離性、定製性強,統一齣入口,只能通過指定的A ...


有些場景下,需要隔離不同的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有問題,導致一直同不不成功,可能會出現一直同步不過去的情況,這種情況可以加上預警+人工干預,這個是概率的事情。

好了,如果大家有什麼好的意見或建議歡迎下方留言評論,謝謝!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 概要 相信很多朋友在程式生涯中,或多或少都會遇到處理媒體流的需求,而且是採用S端處理,排除代碼上課優化的極限,仍然還是需要很長的時間時,比如: 1:百度網盤在播放視頻的時候,如非VIP會員還需要更長甚至直接斷開流; 2:任何直播視頻在轉碼的時候,不論是否VIP,都會有段緩衝時間,已至於觀看者無法達到 ...
  • 什麼是NoSql NoSQL(Not Only SQL),泛指非關係型的資料庫,是對不同於傳統的關係型資料庫的資料庫管理系統的統稱,強調Key-Value Stores和文檔資料庫的優點。為瞭解決大規模數據集合多重數據種類帶來的挑戰而興起的資料庫。有著模式自由,逆規範化,多分區存儲,彈性可擴展,多副 ...
  • 使用ILMerge工具,將C#項目debug目錄下的exe及其依賴的dll文件打包成一個exe文件,直接雙擊就可運行。 使用工具: ILMerge :http://www.microsoft.com/en-us/download/details.aspx?id=17630 ILMerge-GUI:h ...
  • 眾所周知垂直擴展是提升單機的性能的方式,比如提升雙路、四路的CPU運算能力,加大記憶體,更換速度更快的SSD,或者從代碼根本上進行優化和性能提升。水平擴展是提供多台多種伺服器分離單機性能的方式,比如集群,主從,隊列,負載平衡等等。 白話的垂直擴展 現在伺服器都是雲伺服器,單純從單機的硬體性能提升整體性 ...
  • 上一節我們已經介紹了FFmpeg在Net Core中的簡單應用,這一節我們將根據之前的功能需求和解決方案,進行項目的詳細設計工作。 畫個流程圖 先闡述一下流程,如下圖: 整個流程其實非常簡單,客戶端(無論桌面軟體、還是原生APP、還是HTML網頁)通過一個統一的介面進行調用,我們這裡定義這個介面名稱 ...
  • 準備工作: 1:Net Core 2.1 為何要用2.1,因為在macOS 10.13上一個奇怪的問題,請看另一篇博文介紹 2:FFmpeg 版本無所謂,最新即可,安裝教程網上很多,當然也可以使用docker進行ffmpeg的部署,下載地址 http://ffmpeg.org/download.ht ...
  • 在引用官方的qiniu.core的nuget是總是發生錯誤,錯誤如下,所以就在網上找到了一種解決方案,並稍微改進了一番, 以下是引用圖: 第一步:引用nuget(是位大神寫的,官方的qiniu.core用不了) 第二步:新建項目新建控制器視圖、添加配置信息類和讀取配置信息 配置信息類: 配置信息: ...
  • 使用NPOI導入Excel 首先在MVC項目中導入NPOI 查詢NPOI安裝,排序依據,選擇:最高下載量,選擇第一個。 在控制器中創建ExcelController 在Index視圖中寫入代碼: @using (Html.BeginForm("Import", "Excel", FormMethod ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...