日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

实现业务数据的同步迁移 · 思路一

發布時間:2023/12/4 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实现业务数据的同步迁移 · 思路一 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(好雨知時節,大雨 _ _ _)

時不時的呢,會有小伙伴問我這樣的問題:

1、群主,你的.tsv文件是如何生成的?

2、在線項目數據和種子數據的不一樣,可以下么?

3、如果我本地的數據開發好了,如何把新的數據遷到生產環境呢?

01

PART

設計思路

這幾個問題還是問了一段時間后,我感覺是時候需要考慮考慮了,之前一直比較懶或者沒有很好的辦法去處理這個問題,其實今天的辦法也不是最完美的,所以我叫思路一,如果有好的思路歡迎留言和建議,有獎勵喲。

今天就暫時先說說這個簡單的方案吧,比較簡單,就是把數據從一個DB,遷到另一個DB,然后增加一個輸出tsv的功能,看似很簡單,還是用到了一些知識點的:

1、多表聯合,這個是基礎,任何ORM都支持;

2、讀寫分離,但是有2個前提,下文會具體說;

3、事務處理,保證數據一致性嘛;

那下邊就具體說說,如何來實現。

02

PART

開發流程

代碼不是很多,相信一遍就能看懂。

1、獲取集合內完整數據

這里用到了多表聯合查詢,畢竟SqlSugar不像EFCore那樣,可以一次性就把子屬性給全部查詢出來,感覺就像聚合一樣,那在SqlSugar中的寫法有兩種,官方默認的是Mapper好一些

/// <summary> /// 查詢出角色-菜單-接口關系表全部Map屬性數據 /// </summary> /// <returns></returns> public async Task<List<RoleModulePermission>> GetRMPMaps() {return await Db.Queryable<RoleModulePermission>().Mapper(rmp => rmp.Module, rmp => rmp.ModuleId).Mapper(rmp => rmp.Permission, rmp => rmp.PermissionId).Mapper(rmp => rmp.Role, rmp => rmp.RoleId).Where(d => d.IsDeleted == false).ToListAsync(); }

PS:這里我不想再討論各種ORM的孰優孰劣了,那是小孩紙才會干的事兒,我項目EFCore也用,Dapper也會,就醬吧。

2、開啟數據庫讀寫分離模式

既然要數據庫遷移,肯定是需要一個DB轉移到另一個DB,因為我們的項目正好已經實現了讀寫分離模式,那正好利用這個機制,主庫為寫,所以配置為新庫,從庫為讀,所以配置為舊庫。結果是這樣的:

這里要注意四點:

1、既然要遷移數據,那新庫只生成表結構就行,不用初始化數據,False;

2、設置主庫的ConnID;

3、開啟CQRSEnabled開關,并配置主從庫地址;

4、主從庫數據庫類型一致,不然會報錯,畢竟不是多庫模式;

千萬記得新庫是用來寫的,所以是主庫。

那最后啟動項目結果是這樣的:

3、開始遷移

萬事俱備,只欠東風了,這一步就是要遷移數據邏輯了。其實整個項目核心的就是權限聚合部分了,涉及到了四個表:

角色表、菜單表、接口表、關系表。

因為系統用的是整型的自增主鍵ID,所以要考慮好關系表中,rid、mid、pid的值,要與對應表的id是一致的,如果你一直用的的GUID字符串的話,就不用考慮這個問題,無腦的數據遷移就行.

那現在要保證關系表的id問題,我是這么寫的,在MigrateController.cs中:

/// <summary>/// 獲取權限部分Map數據(從庫)/// 遷移到新庫(主庫)/// </summary>/// <returns></returns>[HttpGet]public async Task<MessageModel<string>> DataMigrateFromOld2New(){var data = new MessageModel<string>() { success = true, msg = "" };if (_env.IsDevelopment()){try{// 獲取權限集合數據 var rmps = await _roleModulePermissionServices.GetRMPMaps();// 當然,你可以做個where查詢//rmps = rmps.Where(d => d.ModuleId > 88).ToList();// 開啟事務,保證數據一致性_unitOfWork.BeginTran();var rid = 0;var pid = 0;var mid = 0;var rpmid = 0;// 注意信息的完整性,不要重復添加,確保主庫沒有要添加的數據foreach (var item in rmps){// 角色信息,防止重復添加,做了判斷if (item.Role != null){var isExit = (await _roleServices.Query(d => d.Name == item.Role.Name && d.IsDeleted == false)).FirstOrDefault();if (isExit == null){rid = await _roleServices.Add(item.Role);Console.WriteLine($"Role Added:{item.Role.Name}");}else{rid = isExit.Id;}}// 菜單if (item.Permission != null){pid = await _permissionServices.Add(item.Permission);Console.WriteLine($"Permission Added:{item.Permission.Name}");}// 接口if (item.Module != null){mid = await _moduleServices.Add(item.Module);Console.WriteLine($"Module Added:{item.Module.LinkUrl}");}// 關系if (rid > 0 && pid > 0 && mid > 0){rpmid = await _roleModulePermissionServices.Add(new RoleModulePermission(){IsDeleted = false,CreateTime = DateTime.Now,ModifyTime = DateTime.Now,ModuleId = mid,PermissionId = pid,RoleId = rid,});Console.WriteLine($"RMP Added:{rpmid}");}}_unitOfWork.CommitTran();data.success = true;data.msg = "導入成功!";}catch (Exception){_unitOfWork.RollbackTran();}}else{data.success = false;data.msg = "當前不處于開發模式,代碼生成不可用!";}return data;}

邏輯很簡單,就是獲取到整體數據后,一個個添加到新庫里,然后再添加關系表,保證數據的完整性,然后用事務,如果出錯,可以回滾,保證一致性。

4、查看結果

到了這里,基本就沒有問題了,可以看到數據已經完成了遷移:

(遷移過程,輸出到控制臺)

(數據庫查看新庫,已經有了數據)

這里完全不用膽小你的生產數據庫是否已經有數據了,無論有沒有,添加的權限關系表的id,也一定會和三個子表是一一對應的,且id自增,沒問題。

關于其他用戶表,博客表肯定不需要遷移吧,這些本地環境肯定是沒有的。

那遷移完了數據,如何生成到tsv文件里呢,請往下看。

03

PART

輸出到文件

那現在我們的新庫有了數據,我們就可以切換到單庫模式來從新庫里獲取數據,然后生成到tsv文件里

[HttpGet]public async Task<MessageModel<string>> SaveData2TsvAsync(){var data = new MessageModel<string>() { success = true, msg = "" };if (_env.IsDevelopment()){try{// 取出數據,序列化,自己可以處理判空var rolesJson = JsonConvert.SerializeObject(await _roleServices.Query(d => d.IsDeleted == false));FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Role_New.tsv"), rolesJson, Encoding.UTF8);var permissionsJson = JsonConvert.SerializeObject(await _permissionServices.Query(d => d.IsDeleted == false));FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Permission_New.tsv"), permissionsJson, Encoding.UTF8);var modulesJson = JsonConvert.SerializeObject(await _moduleServices.Query(d => d.IsDeleted == false));FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Modules_New.tsv"), modulesJson, Encoding.UTF8);var rmpsJson = JsonConvert.SerializeObject(await _roleModulePermissionServices.Query(d => d.IsDeleted == false));FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "RoleModulePermission_New.tsv"), rmpsJson, Encoding.UTF8);}catch (Exception){}data.success = true;data.msg = "生成成功!";}else{data.success = false;data.msg = "當前不處于開發模式,代碼生成不可用!";}return data;}

結果我就不展示了,自己試試就可以了。

思考與總結

從上邊的代碼中,我們可以看出來,因為框架已經集成了很多重要的功能,比如讀寫分離和事務處理,所以代碼還是比較簡單的,如果自己從0開始寫,還是比較麻煩的。

現在還有一個問題需要思考下,如果實現不同類型數據庫的生成,這里也是兩種辦法:

1、使用框架的多庫模式,先從庫1獲取數據,然后切換數據庫,再生成到庫2;

2、可以生成到tsv文件里做個跳板,這不過這里有一個問題,就是關系表的id如果不一樣,一定會混亂的,所以這個時候又說到了主鍵用INT還是GUID的問題了,自己處理吧。

還是歡迎大家多多提意見吧,如何對業務數據進行同步遷移,是一個好課題。

總結

以上是生活随笔為你收集整理的实现业务数据的同步迁移 · 思路一的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。