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

mysql 导入数据 设置变量 mysql导入sql数据_sqlserver


图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

mysql 导入数据 设置变量 mysql导入sql数据_mysql_02


12万34787

mysql 导入数据 设置变量 mysql导入sql数据_数据库_03

4.就叨叨到这里,不喜勿喷,有问题欢迎大佬留言帮我指正,感谢!!!