结构化数据迁移到MongoDB遇到的问题总结

前段时间做了个数据迁移的需求,将mysql里的一些结构化数据迁移到mongodb里,主要是一张数据表和N张日志表,虽然已经上线了,但是从一开始调研,到最终解决所有问题的过程,还是挺丰满的,做一次简单记录

 

1、历史数据的迁移

数据迁移首先要保证的是历史数据能够正常增删改查,所以首先历史数据必须先迁移到MongoDB里,可惜默认不能存Long型主键,因此需要考虑数据迁移到MongoDB里,主键的类型情况

2、迁移表主键类型

最直接的方法是新定义一个MongoDB的映射DO,重新定义主键类型,历史数据和新数据都以这种DO格式保存,但这样修改相当多,Service,DAO所有泛型相关,包括公用方法和convert都要改,更关键的一点,关联表之间,以该表主键作为外键的情况

3、关联表

关联表之间,很多表以该迁移表的主键作为外键关联,如果主键类型改变,关联表字段类型都会有冲突,基于以上几点,最终选择了还是保持Long型主键存在MongoDB里

4、主键写入

在Do转换成Document之前,拦截,重写onBeforeConvert方法,设置自定义的主键生成方式

5、主键更新

主键有的用雪花算法,而MongoDB本身就是类雪花算法,分布式一致性,而重新设置为Long型,可以用findAndModify这个原子操作来变更主键,同时弄一个序列collection专门保存起来

6、crud的影响

增删查没什么影响,更新如果想用到update(DO)这种操作,只有用save,只要传了主键ID,就可以做更新操作,可以在spring-data-mongodb的生命周期时间里,onBeforeConvert方法的修改会影响insert和save,上面写入Long型主键insert方法做了修改,导致save方法也会从存在来的主键collection里重新获取而新建,而不是根据传入的主键ID来进行更新操作,因此这里可以继续加一个条件,如果传了主键值,不从序列里取,那么save方法走的就是老流程而进行update

7、历史数据如何保持主键值

上面已经说了,insert已经被修改,从主键collection里面捞值,可历史数据的迁移,要保持主键值,不然其他表里的外键就废了,看上去好像insert没法用,但是历史数据这里迁移的insert是要传主键ID的,否则如何保证ID没变,而这就和上面save方法的解决方案契合了,传了主键值,就不从序列里取,存的就是传入的主键值,简直完美

8、多表聚合查询

先以为MongoDB可能还要用到类似MySQL里面的JOIN之类的操作,后来才发现,连表基本都是一张迁移,一张不迁移,用不到MongoDB里面的@lookup相关操作,后来就干脆MySQL里的查询还是mybatis获取,进而遍历后再过滤MongoDB里的数据,最终聚合起来

9、MVC的修改

DO新增了一个自定义注解的Long型变量,覆盖掉无法修改的Base基类的ID,作为主键ID,Service层可以不做修改,最多换一个调用DAO层变量的名称,DAO层继承的MongoBaseDAO里可以放一些通用的crud和公用方法,IxxxMongoDAO就放具体DAO层操作MongoDB的业务接口

10、配置类

读写分离,writeConcern和readConcern的配置,这主要是集群资源有限,为了安全意见,主节点写入返回

11、事务的支持

这也是个坑,springboot1.5.x和spring-data1.10.x太老,虽然MongoDB支持了事务,但spring-data-mongodb等不支持,导致一些删除回滚操作,MySQL的可以正常回滚,同时关联的MongoDB的没法删除,目前操作相对简单,是在事务回滚抛出异常之前手动回归了相关操作

发表回复