一,目得
给第一次重构数据迁移的同学做一些参考,其中包含一表变多表,一些走过的坑及部分代码参考。
二,选用技术
- 简约无嵌入
- 本文使用spring boot jdbc 重组sql重新写入数据
- 分批迁移
- java8,spring boot2,mysql5.7
三、相关代码
1.数据库连接
public static DataSource getTargetDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.username("*****");
dataSourceBuilder.password("******");
dataSourceBuilder.driverClassName(com.mysql.jdbc.Driver.class.getName());
dataSourceBuilder.url("jdbc:mysql://******/recommend");
return dataSourceBuilder.build();
}
public static DataSource getSourceDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.username("***");
dataSourceBuilder.password("***");
dataSourceBuilder.driverClassName(com.mysql.jdbc.Driver.class.getName());
dataSourceBuilder.url("jdbc:mysql://*******/namecard1");
return dataSourceBuilder.build();
}
2.核心代码
JdbcTemplate jdbcTemplate = new JdbcTemplate(getResourceDataSource());
JdbcTemplate jdbcTemplate2 = new JdbcTemplate(getTargetDataSource());
//分批
Integer begin = 0;
Integer size = 5000
while (true) {
String sql = "SELECT * FROM recommend_log_namecard GROUP BY recommended_member_id LIMIT " + begin + "," + size;
List<Map<String, Object>> membersMap = jdbcTemplate.queryForList(sql);
if (membersMap.size() > 0){
String sqls = getUserRelationSqls(membersMap);
jdbcTemplate2.batchUpdate(sqls);
System.out.println(sqls);
begin += size;
}else {
break;
}
}
3,批SQL组装
public String memberToCentAccountDetail(List<Map<String, Object>> membersMap,Integer moduleId,String key){
Timestamp now = new Timestamp(System.currentTimeMillis());
String prefix = "INSERT INTO `namecard2`.`cent_account_detail` (\n" +
" `module_id`,\n" +
" `module_object_id`,\n" +
" `increase_count`\n" +
") \n" +
"VALUES\n";
StringBuffer suffix = new StringBuffer();
for(Map<String,Object> map:membersMap){
Double integeralCount = Double.valueOf(map.get(key).toString()) *100;
//名片推荐积分
String one = "" +
" (\n" +
" "+moduleId+",\n" +
" '"+map.get("id").toString().replaceAll("'","--") +"',\n" +
" "+ integeralCount.longValue() +"" +
") , ";
suffix.append(one);
}
// 构建完整sql
String sql = prefix + suffix.substring(0, suffix.length() - 2);
return sql;
}
四,坑及需要注意的点
- 数据带有 ' \ 关键字符.使用replaceAll进行转义。 保留的话 加上 ' ,\\
- 数据在新重构里唯一旧数据不唯一,使用group by 保留一个有用的。
- 操作过程千万不要在旧生产上直接操作数据,保留完整 数据,给迁移后数据做认证.
- 使用中间库验证完后,再上新的生产。
- 奇怪的支付 \0x71\0x22 非正经常字符,使用 text = text.replaceAll("[\ud800\udc00-\udbff\udfff\ud800-\udfff]","").replaceAll("\\",""); 去除
- 使用 limit 分页时记得停机,或加上日期。。防止数据会重叠。