1.前提描述
今天接到任务,需要将sqlServer上的老数据同步到生产上的mySql,给我的文件是个xx.mdf,
需要导入的数据量为将近800万,这只是几个月的,后续还有几年的数据要操作,头大的不行不行的
2.解决思路(两种方式都有效,按需选择)
思路1.
1.先将 xx.mdf 导入到sqlServer 中
2.通过navicate 工具直接做数据传输
备注: 刚开始我是使用的这种方式,传输是没有问题的,但是sqlServer数据中有类型为 timestamp ,
查看数据时显示的是(BLOB)8bytes 查看下图1.需要使用sqlServer 函数转换,
此时导入到mysql的数据这个字段对应列为空,因此使用思路二解决问题
思路2.
1.先将 xx.mdf 导入到sqlServer 中
2.通过程序读取sqlServer数据
3.将sqlServer中的数据写入到mySql中(**此时写入到的是我本地的mysql**)
4.确认本地导入的数据没有问题后
4.1生产数据备份
4.2将本地mysql数据导入到生产mysql
图1
3.开始动手
备注: 项目框架 springBoot, myBatis-plus, mysql, sqlServer
1.先将 xx.mdf 导入到sqlServer 中 参考如下命令
EXEC sp_attach_db @dbname = 'sqlServer的数据库名',
@filename1 = 'C:\\1_app\\4_sqlServer\\xxx.mdf';
2.通过程序读取sqlServer数据
//批量同步处理
@Override
public void batch() {
LocalDateTime localDateTime_begin = LocalDateTime.now();
// 查询总条数
Long totalNum = xxxxService.count();
System.out.println("总数: " + totalNum);
if (totalNum > 0) {
//因为数据量大,采用分页,这里计算分页总页数
//Const.limit_batch为一个常量,定义的是分页每页数量
long pages = totalNum / Const.limit_batch + (totalNum % Const.limit_batch != 0 ? 1 : 0);
System.out.println("总页数: " + pages);
long time_begin = System.currentTimeMillis();
int total = 0;
for (int i = 1; i <= pages; i++) {
// 根据条数分页,查询前 n=Const.limit_batch 条
Page<SqlServerVOrder> sqlServerVOrderPage = new Page<>();
sqlServerVOrderPage.setSize(Const.limit_batch);
sqlServerVOrderPage.setCurrent(i);
//这里排序可根据实际需求更改或删除掉
sqlServerVOrderPage.addOrder(OrderItem.asc("时间戳"));
IPage<SqlServerVOrder> sqlServerVOrderIPage = xxxxService.page(sqlServerVOrderPage);
// 进行数据转换
if (CollUtil.isNotEmpty(sqlServerVOrderIPage.getRecords())) {
List<MySqlOrder> addMySqlOrders = new ArrayList<>();
for (SqlServerVOrder record : sqlServerVOrderIPage.getRecords()) {
//这里做sqlServer数据转换为mySql数据实体
MySqlOrder mySqlOrder = new MySqlOrder();
mySqlOrder.setOrderNo(record.getxxx());
//重点来了,这里就是为了转换这个时间戳,上面图1可见,其实这个就是个16进制的数据
mySqlOrder.setTimeStamp(record.xxx时间戳xxx());
//这里这个字段是我的mysql需要的,通过sqlServer的时间戳转换为int,
//通过上面的page查询后这里进行赋值实际是没有值的,我这里是在
//数据都同步后,直接在mysql中update 该字段,使用mysql函数
// conv('需要转换的字段', 16, 10)
//如 update 表名 set 时间戳Int = conv('时间戳', 16, 10) where xx is null
mySqlOrder.setTimeStampInt(record.xxx时间戳Intxxx());
addMySqlOrders.add(mySqlOrder);
}
System.out.println("总条数 " + totalNum + "总页码: " + pages + "当前begin 页码" + i + " " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
long time = System.currentTimeMillis();
// this.saveBatch(addMySqlOrders,Const.limit_batch);
// this.saveBatch(addMySqlOrders);
//注意看这里,我没有用mybatis-plus 提供的saveBatch(),测试每有这个拼接的效率高,有说在链接上加配置&rewriteBatchedStatements=true,加了用自带的saveBatch也没好用,有好用的兄弟欢迎指导下
mySqlOrderMapper.batchSaveMySqlOrder(addMySqlOrders);
long time1 = System.currentTimeMillis();
System.out.println("批量插入" + (double) addMySqlOrders.size() / 10000 + "W条数据耗时:" + (time1 - time) + "ms");
System.out.println("总条数 " + totalNum + "总页码: " + pages + " 当前end 页码 " + i + " " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
total = total + addMySqlOrders.size();
}
if (i == 5){
//这里测试两万条,每页数量为4000, 数据量太大会报个错,改个mysql配置就ok了
break;
}
}
long time_end = System.currentTimeMillis();
System.out.println("整体批量插入" + (double) total / 10000 + "W条数据耗时:" + (time_end - time_begin) + "ms");
}
System.out.println("beginLocalDateTime" + localDateTime_begin.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
LocalDateTime localDateTime_end = LocalDateTime.now();
System.out.println("localDateTime_end " + localDateTime_end.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//时间间隔
Duration duration = Duration.between(localDateTime_begin, localDateTime_end);
System.out.println("总条数 " + totalNum + " 插入耗时 " + duration.toMillis() + "ms");
}
dao层 该继承谁继承谁
mySqlOrderMapper 接口
void batchSaveMySqlOrder(List<你自己的实体类型> arr);
mapper
<insert id="batchSaveMySqlOrder" parameterType="java.util.List">
insert into tableName values
<foreach collection="list" item="tt" index="index" separator=",">
(
....n个字段
#{tt.xxxtimeStampxxx},
#{tt.xxxtimeStampIntxxx}
)
</foreach>
</insert>
到此代码阶段就完事了,其实没啥玩意,别忙着执行
在执行前需要修改下boot的配置
2万条6401ms
12万34787
4.就叨叨到这里,不喜勿喷,有问题欢迎大佬留言帮我指正,感谢!!!