# oracle-tidb-migrate-java **Repository Path**: yao-coder/oracle-tidb-migrate-java ## Basic Information - **Project Name**: oracle-tidb-migrate-java - **Description**: 用于离线环境的 Oracle -> TiDB **数据**迁移工具(默认支持断点续传、重试、行数校验)。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-09 - **Last Updated**: 2026-04-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Oracle to TiDB Migrator 这是 Oracle -> TiDB 全量数据迁移的 Spring Boot 编排服务。当前版本按“已有 Oracle/TiDB 封装 jar 可自动读取配置并注入 Bean”的方式改造:本项目不再自己读取数据库连接、不再 `DriverManager` 建连,也不内置 Oracle/MySQL JDBC driver。 项目只负责: - 暴露 3 个 `POST` 接口 - 创建迁移/重跑/校验任务 - 按表维度编排迁移和状态更新 - 提供默认 Spring JDBC Mapper,或调用外部 jar 注入的 Mapper ## 外部 jar 对接方式 推荐方式:你的封装 jar 从 `application.yml` 自动读取 Oracle/TiDB 配置,并向 Spring 容器注入两个数据源 Bean: | Bean 名称 | 作用 | |------|------| | `oracleDataSource` | Oracle 源库数据源 | | `tidbDataSource` | TiDB 目标库和元数据表数据源 | 本项目会在缺少 Mapper Bean 时自动启用默认 Spring JDBC 实现: | Bean 接口 | 作用 | |------|------| | `com.cmb.basicdataservice.infrastructure.migration.mapper.OracleMigrationMapper` | 查询 Oracle 列、行数、分页数据、抽样行 | | `com.cmb.basicdataservice.infrastructure.migration.mapper.TidbMigrationMapper` | 检查 TiDB 目标表、分页删除、批量写入、行数和抽样行 | | `com.cmb.basicdataservice.infrastructure.migration.mapper.MigrationMetadataMapper` | 使用 `tidbDataSource` 读写 `migration_task`、`migration_task_detail`、`migration_table_config` | 如果你已有 Mapper 的 SQL 和事务封装更完整,也可以直接在外部 jar 里注入上面 3 个 Mapper 接口 Bean。本项目的默认 JDBC Mapper 使用 `@ConditionalOnMissingBean`,检测到外部 Mapper 后会自动让位。 ## application.yml 本项目只保留迁移编排参数。Oracle/TiDB 连接配置由你的外部 jar 自己读取和绑定,并最终注入 `oracleDataSource`、`tidbDataSource` 或 3 个 Mapper Bean。 ```yaml server: port: 8080 migration: log-level: INFO retries: 3 retry-wait-sec: 2 retry-backoff-multiplier: 2.0 retry-max-wait-sec: 30 max-workers: 1 batch-size: 5000 commit-every-rows: 1000 target-delete-page-size: 90000 validation-sample-size: 10 ``` | 字段 | 说明 | |------|------| | `max-workers` | 单个任务内并行处理的表数量 | | `batch-size` | Oracle 每批拉取行数,表级配置可覆盖 | | `commit-every-rows` | TiDB Mapper 批量写入调用的行数边界,默认 1000 | | `target-delete-page-size` | 迁移前清空目标表的分页大小,默认 90000 | | `validation-sample-size` | 校验接口默认 N | | `retries` / `retry-*` | 本项目对 Mapper 调用外层重试的参数 | ## Mapper 契约 ### OracleMigrationMapper ```java List listColumns(TableQuery table); long countRows(TableQuery table); List fetchRows(FetchRowsQuery query); Object[] fetchRowAt(SampleRowQuery query); ``` 默认实现行为: - `listColumns` 返回 Oracle 源表列名,顺序必须和迁移写入列顺序一致。 - `fetchRows` 有主键时按主键分页;无主键时按 Oracle `ROWID` 分页,并在最后一列附加游标值。 - `fetchRowAt` 用于校验,按主键或物理行号排序取第 `position` 行。 ### TidbMigrationMapper ```java boolean tableExists(TableQuery table); int deletePageByRowId(DeletePageCommand command); int deletePage(DeletePageCommand command); void insertRows(InsertRowsCommand command); long countRows(TableQuery table); Object[] fetchRowAt(SampleRowQuery query); ``` 默认实现行为: - `tableExists` 必须在迁移前确认目标表是否存在。 - `deletePageByRowId` 优先使用 TiDB `_tidb_rowid` 删除一页;不支持时请抛 `UnsupportedOperationException`,编排层会退化调用 `deletePage`。 - `deletePage` 每次删除 `pageSize` 行,不关心业务主键。 - `insertRows` 每次最多接收 `migration.commit-every-rows` 行;默认 JDBC 实现每次 `batchUpdate` 是一次调用边界。 - `fetchRowAt` 用于校验,按主键或 `_tidb_rowid` 排序取第 `position` 行。 ### MigrationMetadataMapper 负责 3 张元数据表: | 表名 | 作用 | |------|------| | `migration_task` | 任务表 | | `migration_task_detail` | 表级任务详情表 | | `migration_table_config` | 待迁移表配置表 | 接口方法位于 `src/main/java/com/cmb/basicdataservice/infrastructure/migration/mapper/MigrationMetadataMapper.java`。其中 `insertTaskDetail` 必须回填 `detailId`,后续状态更新依赖这个 ID。 默认 JDBC 元数据 Mapper 依赖固定字段名,建表参考 [docs/metadata-schema.sql](docs/metadata-schema.sql)。 ## API 只保留 3 个接口,全部为 `POST`。 ### 1. 异步迁移 ```bash curl -X POST http://localhost:8080/api/migrations/tasks ``` 行为: 1. 通过 `MigrationMetadataMapper.selectEnabledTables()` 查询启用表。 2. 创建 `MIGRATE` 任务和表级详情。 3. 后台迁移每张表。 4. 表级状态、时间、耗时、迁移行数、删除行数写入详情表。 ### 2. 失败重跑 ```bash curl -X POST http://localhost:8080/api/migrations/retry-failed \ -H "Content-Type: application/json" \ -d '{"taskId":"source-task-id"}' ``` 行为:查询来源任务下状态为 `FAILED` 的表,复制当时的表配置快照,创建新的 `RETRY` 任务后台执行。 ### 3. 数据准确性验证 ```bash curl -X POST http://localhost:8080/api/migrations/verify \ -H "Content-Type: application/json" \ -d '{"taskId":"source-task-id","sampleSize":10}' ``` `taskId` 可选: - 传入时,只验证该任务下迁移成功的表。 - 不传时,验证所有启用表。 验证内容: - Oracle/TiDB 行数对比 - 第 N 行、中间行、最后 N 行逐列对比 - 结果同步返回,并写入 `migration_task_detail.validation_result` ## 迁移流程 1. 读取 `migration_table_config` 中启用表。 2. 创建任务和表级详情。 3. 每张表开始前调用 TiDB Mapper 检查目标表是否存在。 4. 目标表存在时分页删除旧数据,每页默认 90000 行。 5. Oracle Mapper 按主键或 `ROWID` 分页查询。 6. TiDB Mapper 每次写入最多 1000 行,作为提交边界。 7. 单表成功或失败都更新 `migration_task_detail`。 8. 所有表结束后汇总更新 `migration_task`。 ## 初始化表配置 元数据表建表参考 [docs/metadata-schema.sql](docs/metadata-schema.sql)。原 `migrate_config.json` 中的表配置已整理到 [docs/metadata-init.sql](docs/metadata-init.sql),请在元数据表建好后执行一次。 ## 验证 ```bash mvn -q test ``` 注意:运行时至少需要满足一种注入方式: - 外部 jar 注入 `oracleDataSource` 和 `tidbDataSource`,使用本项目默认 JDBC Mapper。 - 外部 jar 直接注入 3 个 Mapper 接口 Bean,覆盖默认 JDBC Mapper。