avatar

目录
数据迁移怎么做?

数据迁移怎么做的?

  • 1、订单表到履约表找字段映射,即两个不同库表先做好数据字段的对应和补齐;

  • 2、代码程序(java)做功能,从一个数据库表中读出数据,然后写到另一个数据库表中;

技术历练点

  • 多线程;
    • 使用线程池:
    • 确定核心线程池的数量;
  • 使用多线程后,怎么精确确定迁移任务结束时间;
    • 使用原子类:AtomicInteger; java Future<?> submit = creedMigrationThreadPoolExecutor.submit(creedTask);
    • 使用Future列表存放每个线程任务句柄,如果列表中所有任务都结束了,则整个任务结束;
  • 批量读写;
    • 批量从A表读数据,关键是向B表写数据时,需完全避免单条数据插入数据库,要以批量形式;
    • 如果有关联关系时,需要依赖上次的主键ID的,在批量创建数据后,直接利用对象数据的信息,避免批量再从数据库取数据;
  • 同一个项目中两套数据源配置;
    • transactionManager;
    • 具体参见底页代码示例;
    • java @Transactional(transactionManager = "creedTransactionManager", rollbackFor = Exception.class)
  • 日志监控;
    • 关键节点日志;
    • 失败信息日志;
    • StopWatch监控各代码块耗时占比,以便后续优化;
  • 先迁移基本信息,后RPC补充缺失的信息;
    • 避免RPC耗时较长,数据异常时阻塞流程;
  • 怎么保证不会迁移重复数据?
    • 取原始数据的时候是无交叉分段取值(0,999)(1000,1999)等;
    • 可以给主键加唯一索引;
    • 程序中使用SHA算法提取分段id的摘要,然后放进缓存中,下一批次数据来的时候先判断摘要是否存在,如果存在则跳过;
  • 批量迁移过程中不断初始化新对象也较为耗时,可以使用设计模式之对象池模式;类似于线程池和连接池。
  • 切记要记得对称两边表字段的大小,不要因为字段多长导致线程挂起失败;
  • 迁移数据怎么设计成增量迁移,不要因为部分数据问题导致删库-重新迁移;
    • Redis记录失败的数据ID;
    • 数据分段,记录失败的开始和结束位置;
  • 对外提供的迁移接口要做异步处理;
  • 对于迁移过程中出现的异常,一定要打印日志(最好是error级别的),方便具体问题排查(20200411加班就是因为错误日志用的info级别,导致排查了好几个小时,大大增加无效工作时间);
  • 优化分页查询
    • 利用索引ID,可优化分页查询效率;(大批量数据要利用索引,在我们的项目中最初使用 limit-size方式分页取值,发现越往后分页取值越慢)
Code
1
2
3
4
5
<select id="batchSelectOrders" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from db_trade.zcy_orders where id > #{id,jdbcType=BIGINT} and need_done_migration = 1 order by id limit #{size}
</select>

技术提升/优化

迁移关注点:

  • 第一版:主要注重数据准确性;
  • 第二版:优化迁移速度;刚开始33条/秒 -> 80条/秒 -> 1000条/秒;(这里是以订单维度,一条订单关联的数据也有二十多条之多)
  • 数据源配置简示:
    java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    /**
    * db_creed数据库实例链接类
    *
    * @date 2019/4/20
    * @author C.A.O
    */
    @Configuration
    @MapperScan(basePackages = "cn.gov.zcy.trade.creed.migration.dal.creed.dao", sqlSessionTemplateRef = "creedSqlSessionTemplate")
    public class DbCreedConfig {

    /**
    * mapper-locations 配置
    */
    @Value("${creed.mybatis.mapper-locations}")
    private String creedMapperLocation;

    @Bean(name = "creedDataSource")
    @ConfigurationProperties(prefix = "creed.mybatis")
    public DataSource creedDataSource() {
    return DataSourceBuilder.create().build();
    }


    @Bean(name = "creedSqlSessionFactory")
    public SqlSessionFactory creedSqlSessionFactory(@Qualifier("creedDataSource") DataSource dataSource) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(creedMapperLocation));
    return bean.getObject();
    }

    @Bean(name = "creedTransactionManager")
    public DataSourceTransactionManager testTransactionManager(@Qualifier("creedDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "creedSqlSessionTemplate")
    public SqlSessionTemplate creedSqlSessionTemplate(@Qualifier("creedSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
    return new SqlSessionTemplate(sqlSessionFactory);
    }
    }
    ```
文章作者: 海东青
文章链接: https://haohaogit.github.io/2020/03/12/%E6%95%B0%E6%8D%AE%E8%BF%81%E7%A7%BB%E6%80%8E%E4%B9%88%E5%81%9A%EF%BC%9F/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hexo
打赏
  • 微信
    微信
  • 支付宝
    支付宝