(好雨知时节,大雨 _ _ _)

时不时的呢,会有小伙伴问我这样的问题:

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的问题了,自己处理吧。

还是欢迎大家多多提意见吧,如何对业务数据进行同步迁移,是一个好课题。

实现业务数据的同步迁移 · 思路一相关推荐

  1. 企业级数据仓库:数据仓库概述;核心技术框架,数仓理论,数据通道Hive技术框架,HBase设计,系统调度,关系模式范式,ER图,维度建模,星型/雪花/星座模式,数据采集同步,业务数据埋点,数据仓库规范

    文章目录 第一章 数据仓库概述 1.1 数据仓库简介 1.1.2 什么是数据仓库? 1.1.3 OLTP 与 OLAP 1.2 数据仓库技术架构 1.3 课程目标 第二章 核心技术框架 2.1 数据仓 ...

  2. 物化视图(materialized view) 实现数据迁移、数据定时同步

    近日公司有一个9i 的Oracle数据库,运行效率低下.想要将其升级到11G. 但是升级之前 要将数据进行同步,好在表不是很多.只有三张表.业务压力也不大,就想到了使用物 化视图的方式将数据同步过来. ...

  3. 同步亚马逊产品广告(SP)业务数据

    序言 亚马逊提供 snapshot 快照功能,实现您构建的系统与亚马逊广告业务数据同步.同步的目的是做分页辅助之类(比如:广告活动查询,接口未提供总记录数,我们就无法实现分页功能,如果把广告活动数据同 ...

  4. 一面数据: Hadoop 迁移云上架构设计与实践

    背景 一面数据创立于 2014 年,是一家领先的数据智能解决方案提供商,通过解读来自电商平台和社交媒体渠道的海量数据,提供实时.全面的数据洞察.长期服务全球快消巨头(宝洁.联合利华.玛氏等),获得行业 ...

  5. Laravel学习笔记4,文件上传,分页,验证码,数据表和迁移

    目录 一.文件上传 二.数据分页 三.验证码 Return Image Return URL Return HTML 六.响应处理 一.文件上传 在laravel, 里面实现文件的上传是很简单的,压根 ...

  6. Sersync和lsyncd实现数据实时同步

    文章目录 一.实时同步概念 1. 什么是实时同步 2. 实时同步原理 3. 实时同步的场景 4. 实时同步工具 二.实时同步案例 1.环境准备 2.配置思路 3.nfs服务端配置(172.16.1.3 ...

  7. binlog流程 mysql_小米 MySQL 数据实时同步到大数据数仓的架构与实践

    背景MySQL由于自身简单.高效.可靠的特点,成为小米内部使用最广泛的数据库,但是当数据量达到千万/亿级别的时候,MySQL的相关操作会变的非常迟缓:如果这时还有实时BI展示的需求,对于mysql来说 ...

  8. TiDB 在知乎万亿量级业务数据下的实践和挑战

    作者 | 朱小厮的博客 来源 | https://mp.weixin.qq.com/s/fpWjcDGatuqUUq36K8-3Jw 一.业务场景 知乎从问答起步,在过去的 8 年中逐步成长为一个大规 ...

  9. 小米 MySQL 数据实时同步到大数据数仓的架构与实践

    背景 MySQL由于自身简单.高效.可靠的特点,成为小米内部使用最广泛的数据库,但是当数据量达到千万/亿级别的时候,MySQL的相关操作会变的非常迟缓:如果这时还有实时BI展示的需求,对于mysql来 ...

最新文章

  1. CDN的工作原理以及其中的一些技术-阿里
  2. 计算机视觉开源库OpenCV之利用开操作(Opening Operation)修复受损照片方法
  3. ACM入门之【KMP】
  4. Mongodb参数详解(参考:http://blog.csdn.net/freebird_lb/article/details/8229567)
  5. python 广告拦截_Python如何在抓取时欺骗反广告块过滤器?
  6. java链式调用空指针_java 链式调用
  7. c语言中格式化字符串系列函数包括,解析C语言中常用的格式化输入、输出函数...
  8. 计算机组成原理CRC相关运算,计算机专业基础综合计算机组成原理(数据的表示和运算)-试卷1...
  9. MongoDB学习——介绍一款MongoDB连接管理工具
  10. 模块化的ESP8266小电视设计与制作
  11. 多种Map简单使用和测试
  12. 第十一个Java程序,计算QQ等级。
  13. STM32物联网套件基础版03-控制继电器
  14. 学计算机主修,大学计算机专业自我介绍(精选5篇)
  15. LDO和DCDC电路的区别以及PCB设计选择
  16. 【TIPC】三、Messaging
  17. diag()函数功能
  18. soul网关-2-divide插件
  19. 【android】超级详细Android Studio下载安装教程(附:JDK1.8安装教程)
  20. 利用C++调用天气webservice-gSOAP方法

热门文章

  1. QtWebkit中浏览器插件的设计-1
  2. 代码收藏——js+asp 的屏幕滚动脚本
  3. 接口文档神器Swagger(下篇)
  4. 使用SMART监控Ubuntu
  5. Linux shell 编程(七):流程控制语句
  6. CenterOS x64安装serv-U
  7. 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
  8. ***Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1)(平均)。hash特别适合用于存储对象...
  9. TTL expired in transit--问题篇~
  10. ABP vNext微服务架构详细教程——结束语