由于业务需求,需要将数据从mysql上迁移到mongo上,我从网络上查了一下资料,网上的方案大多是使用工具导出,但我觉得很麻烦,于是打算自己用golang写个小程序来完成这个功能
迁移思路
1、一般方式
一般的方式是先根据数据表的定义,在golang中定义一个结构体,打上对应的tag,然后使用sqlx来将读取到的数据反序列化到结构体中来,然后再序列化成mongo的document插入数据库。过程如下:
mysql -> 读取 -> []byte(这个是反序列化之前的数据) -> 结构体 -> 插入数据库
但其实这样做有一个很麻烦的地方,我需要先根据每一个表的结构来定义一个结构体,每多一个表,我就需要手动来添加一个结构体,程序的灵活性非常堪忧。
2、另辟蹊径
其实在sql包查询的时候,其实是可以获得表里面每一列的类型信息和列名,我们可以根据这些类型信息,将上面过程中的[]byte 转化为相应的类型。不过中间比较麻烦的地方在于,这些类型并不仅仅是golang的基本类型,比如int、string等,而且也包括sql包包装过的类型,如sql.NullInt64等(参见 database/sql/sql.go),所以中间会经历两次类型的转化。过程如下:
mysql -> 读取 -> []byte -> sql.NullInt64等类型 ->int,string 等基本类型 -> 列名和值组成的map -> 插入数据库
3、会遇到的问题
如何将[]byte转化为 sql.NullInt64类型?rows.Scan(dest …interface{})方法的作用是将[]byte 给转化为dest 对应的类型,它会先查看dest的类型,如果是一般的类型都可以很简单的转化,但如果是比较复杂的类型该怎么办呢? 此时它会看dest是否实现了Scanner 接口(接口定义:Scan(src interface{}) error,注意区别这个Scan跟rows.Scan是不一样的)。说白了它的逻辑就是rows.Scan不知道如何将一个[]byte 给转化为一个复杂的结构体,但是这个结构体实现了Scanner接口,说明他自己知道如何把[]byte转化为他自己,那rows.Scan就把转化的任务交给Scanner吧!而刚好 sql.NullInt64就是一个Scanner,所以调用我们只需要给 rows.Scan一个sql.NullInt64对象的interface{}就好啦
如何获得一个sql.NullInt64的对象的interface{} ?读者可能会想,可以直接在代码里面写一个空的sql.NullInt64的对象然后再转成interface{}就好了。但是,由于这个小程序并不是针对某一个确定的数据表的&#x