我来为您提供一个完整的Java系统迁移案例,包括代码实现和详细说明。

系统迁移案例:从单体架构到微服务
项目背景
将传统单体应用迁移到Spring Cloud微服务架构,实现系统的可扩展性和维护性。
核心代码实现
1 数据迁移工具类
package com.example.migration.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.ResultSetMetaData;
import java.util.*;
/**
* 历史数据迁移工具类
*/
@Component
public class DataMigrationUtil {
private static final Logger logger = LoggerFactory.getLogger(DataMigrationUtil.class);
private final DataSource sourceDataSource;
private final DataSource targetDataSource;
private final JdbcTemplate sourceJdbcTemplate;
private final JdbcTemplate targetJdbcTemplate;
private final int BATCH_SIZE = 1000;
public DataMigrationUtil(DataSource sourceDataSource, DataSource targetDataSource) {
this.sourceDataSource = sourceDataSource;
this.targetDataSource = targetDataSource;
this.sourceJdbcTemplate = new JdbcTemplate(sourceDataSource);
this.targetJdbcTemplate = new JdbcTemplate(targetDataSource);
}
/**
* 迁移全表数据
* @param tableName 表名
* @param query 查询语句
* @throws Exception 迁移异常
*/
public void migrateTable(String tableName, String query) throws Exception {
logger.info("开始迁移表: {} 数据", tableName);
// 获取源表所有数据
List<Map<String, Object>> rows = sourceJdbcTemplate.queryForList(query);
logger.info("源表 {} 共有 {} 条数据", tableName, rows.size());
// 分批次迁移
for (int i = 0; i < rows.size(); i += BATCH_SIZE) {
int end = Math.min(i + BATCH_SIZE, rows.size());
List<Map<String, Object>> batch = rows.subList(i, end);
migrateBatch(tableName, batch);
logger.info("已迁移 {}/{} 条数据", end, rows.size());
}
logger.info("完成迁移表: {} 数据", tableName);
}
/**
* 迁移一批数据
*/
@SuppressWarnings("unchecked")
private void migrateBatch(String tableName, List<Map<String, Object>> rows) {
if (rows.isEmpty()) return;
Map<String, Object> firstRow = rows.get(0);
List<String> columns = new ArrayList<>(firstRow.keySet());
// 构建INSERT语句
StringBuilder insertSQL = new StringBuilder()
.append("INSERT INTO ").append(tableName).append(" (")
.append(String.join(", ", columns))
.append(") VALUES (");
for (int i = 0; i < columns.size(); i++) {
insertSQL.append(i == 0 ? "?" : ", ?");
}
insertSQL.append(")");
// 批量插入
targetJdbcTemplate.batchUpdate(insertSQL.toString(), new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int rowNum) throws SQLException {
Map<String, Object> row = rows.get(rowNum);
for (int i = 0; i < columns.size(); i++) {
Object value = row.get(columns.get(i));
ps.setObject(i + 1, value);
}
}
@Override
public int getBatchSize() {
return rows.size();
}
});
}
/**
* 迁移增量数据
* @param tableName 表名
* @param lastMigrateTime 上次迁移时间
*/
public void migrateIncremental(String tableName, Date lastMigrateTime) throws Exception {
String query = "SELECT * FROM " + tableName + " WHERE create_time > ?";
List<Map<String, Object>> rows = sourceJdbcTemplate.queryForList(query, lastMigrateTime);
if (!rows.isEmpty()) {
migrateTable(tableName, query);
}
}
}
2 服务迁移器
package com.example.migration.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 服务迁移管理器
*/
@Component
public class ServiceMigrationManager {
private static final Logger logger = LoggerFactory.getLogger(ServiceMigrationManager.class);
@Autowired
private LegacyService legacyService;
@Autowired
private MicroService microService;
private ExecutorService executor = Executors.newFixedThreadPool(4);
/**
* 执行服务迁移
*/
public void executeMigration() {
logger.info("开始执行服务迁移...");
// 并行执行迁移
CompletableFuture<Void> orderFuture = CompletableFuture.runAsync(() -> {
migrateOrderData();
}, executor);
CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
migrateUserData();
}, executor);
CompletableFuture<Void> productFuture = CompletableFuture.runAsync(() -> {
migrateProductData();
}, executor);
CompletableFuture<Void> inventoryFuture = CompletableFuture.runAsync(() -> {
migrateInventoryData();
}, executor);
// 等待所有迁移完成
CompletableFuture.allOf(orderFuture, userFuture, productFuture, inventoryFuture).join();
logger.info("服务迁移完成");
}
/**
* 迁移订单数据
*/
private void migrateOrderData() {
try {
// 从旧系统获取订单数据
List<Order> legacyOrders = legacyService.getLegacyOrders();
// 转换并迁移数据
List<NewOrder> newOrders = legacyOrders.stream()
.map(OrderConverter::convertToNewOrder)
.collect(Collectors.toList());
// 插入到新系统
microService.saveOrders(newOrders);
logger.info("订单数据迁移完成,共迁移 {} 条", newOrders.size());
} catch (Exception e) {
logger.error("订单数据迁移失败", e);
}
}
/**
* 迁移用户数据
*/
private void migrateUserData() {
try {
List<LegacyUser> legacyUsers = legacyService.getLegacyUsers();
List<NewUser> newUsers = legacyUsers.stream()
.map(UserConverter::convertToNewUser)
.collect(Collectors.toList());
microService.saveUsers(newUsers);
logger.info("用户数据迁移完成,共迁移 {} 条", newUsers.size());
} catch (Exception e) {
logger.error("用户数据迁移失败", e);
}
}
/**
* 迁移产品数据
*/
private void migrateProductData() {
try {
List<Product> products = legacyService.getCompatibleProducts();
microService.saveProducts(products);
logger.info("产品数据迁移完成,共迁移 {} 条", products.size());
} catch (Exception e) {
logger.error("产品数据迁移失败", e);
}
}
/**
* 迁移库存数据
*/
private void migrateInventoryData() {
try {
List<Inventory> inventories = legacyService.getInventories();
microService.saveInventories(inventories);
logger.info("库存数据迁移完成,共迁移 {} 条", inventories.size());
} catch (Exception e) {
logger.error("库存数据迁移失败", e);
}
}
}
3 数据转换器
package com.example.migration.converter;
import com.example.legacy.model.LegacyOrder;
import com.example.legacy.model.LegacyUser;
import com.example.microservice.model.NewOrder;
import com.example.microservice.model.NewUser;
/**
* 数据转换器
*/
public class DataConverters {
/**
* 旧订单转换为新订单
*/
public static NewOrder convertToNewOrder(LegacyOrder legacyOrder) {
return NewOrder.builder()
.id(legacyOrder.getOrderId())
.userId(legacyOrder.getCustomerId())
.amount(legacyOrder.getTotalAmount())
.status(mapOrderStatus(legacyOrder.getStatus()))
.createdTime(legacyOrder.getOrderTime())
.updatedTime(legacyOrder.getUpdateTime())
.build();
}
/**
* 旧用户转换为新用户
*/
public static NewUser convertToNewUser(LegacyUser legacyUser) {
return NewUser.builder()
.id(legacyUser.getUserId())
.username(legacyUser.getUserName())
.email(legacyUser.getEmailAddress())
.phone(legacyUser.getPhoneNumber())
.status(mapUserStatus(legacyUser.getStatus()))
.createdTime(legacyUser.getRegisterTime())
.build();
}
/**
* 映射订单状态
*/
private static String mapOrderStatus(String legacyStatus) {
switch (legacyStatus) {
case "0": return "PENDING";
case "1": return "PAID";
case "2": return "SHIPPED";
case "3": return "COMPLETED";
case "4": return "CANCELLED";
default: return "UNKNOWN";
}
}
/**
* 映射用户状态
*/
private static String mapUserStatus(String legacyStatus) {
switch (legacyStatus) {
case "0": return "ACTIVE";
case "1": return "INACTIVE";
case "2": return "FROZEN";
default: return "UNKNOWN";
}
}
}
4 迁移监控器
package com.example.migration.monitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicLong;
/**
* 迁移监控器
*/
@Component
public class MigrationMonitor {
private static final Logger logger = LoggerFactory.getLogger(MigrationMonitor.class);
private final AtomicLong totalCount = new AtomicLong(0);
private final AtomicLong successCount = new AtomicLong(0);
private final AtomicLong failCount = new AtomicLong(0);
private final Map<String, Long> tableProgress = new ConcurrentHashMap<>();
/**
* 记录成功迁移
*/
public void recordSuccess(String tableName, int count) {
successCount.addAndGet(count);
totalCount.addAndGet(count);
tableProgress.put(tableName, (long) count);
}
/**
* 记录失败迁移
*/
public void recordFail(String tableName, int count) {
failCount.addAndGet(count);
logger.error("数据表 {} 迁移失败 {} 条", tableName, count);
}
/**
* 定时打印迁移进度
*/
@Scheduled(fixedDelay = 60000)
public void printProgress() {
logger.info("========== 迁移进度报告 ==========");
logger.info("总迁移数量: {}", totalCount.get());
logger.info("成功数量: {}", successCount.get());
logger.info("失败数量: {}", failCount.get());
logger.info("成功率: {:.2f}%",
successCount.get() * 100.0 / totalCount.get());
if (!tableProgress.isEmpty()) {
logger.info("各表迁移进度: {}", tableProgress);
}
logger.info("===================================");
}
/**
* 导出迁移报告
*/
public MigrationReport generateReport() {
return MigrationReport.builder()
.total(totalCount.get())
.success(successCount.get())
.fail(failCount.get())
.tableProgress(new HashMap<>(tableProgress))
.successRate(successCount.get() * 100.0 / totalCount.get())
.build();
}
}
5 配置类
package com.example.migration.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* 迁移配置
*/
@Configuration
public class MigrationConfig {
/**
* 数据源配置
*/
@Bean
@ConfigurationProperties(prefix = "source.datasource")
public DataSource sourceDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "target.datasource")
public DataSource targetDataSource() {
return DataSourceBuilder.create().build();
}
/**
* 事务管理器
*/
@Bean
public PlatformTransactionManager transactionManager(DataSource targetDataSource) {
return new DataSourceTransactionManager(targetDataSource);
}
/**
* 迁移线程池
*/
@Bean
public ThreadPoolTaskExecutor migrationTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("migration-");
return executor;
}
}
6 主程序
package com.example.migration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.boot.CommandLineRunner;
import com.example.migration.service.ServiceMigrationManager;
import com.example.migration.util.DataMigrationUtil;
@SpringBootApplication
@EnableScheduling
public class SystemMigrationApplication implements CommandLineRunner {
private final ServiceMigrationManager migrationManager;
private final DataMigrationUtil dataMigrationUtil;
public SystemMigrationApplication(ServiceMigrationManager migrationManager,
DataMigrationUtil dataMigrationUtil) {
this.migrationManager = migrationManager;
this.dataMigrationUtil = dataMigrationUtil;
}
public static void main(String[] args) {
SpringApplication.run(SystemMigrationApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println("开始系统迁移...");
// 1. 预检查
preCheck();
// 2. 数据迁移
migrateData();
// 3. 服务迁移
migrationManager.executeMigration();
// 4. 后验证
postVerification();
System.out.println("系统迁移完成!");
}
/**
* 预检查
*/
private void preCheck() {
System.out.println("执行迁移前检查...");
// 检查目标系统可用性
// 检查数据库连接
// 校验数据完整性
}
/**
* 数据迁移
*/
private void migrateData() throws Exception {
System.out.println("开始数据迁移...");
// 迁移字典数据
dataMigrationUtil.migrateTable("sys_dict",
"SELECT * FROM sys_dict WHERE del_flag = 0");
// 迁移用户数据
dataMigrationUtil.migrateTable("sys_user",
"SELECT * FROM sys_user WHERE del_flag = 0");
// 迁移角色数据
dataMigrationUtil.migrateTable("sys_role",
"SELECT * FROM sys_role WHERE del_flag = 0");
System.out.println("数据迁移完成");
}
/**
* 后验证
*/
private void postVerification() {
System.out.println("执行迁移后验证...");
// 验证数据一致性
// 验证API可用性
// 验证系统功能
}
}
配置文件 application.yml
spring:
datasource:
# 源数据库配置
source:
url: jdbc:mysql://old-server:3306/legacy_db
username: old_user
password: old_password
driver-class-name: com.mysql.cj.jdbc.Driver
# 目标数据库配置
target:
url: jdbc:mysql://new-server:3306/microservice_db
username: new_user
password: new_password
driver-class-name: com.mysql.cj.jdbc.Driver
# 迁移配置
migration:
batch-size: 1000
max-threads: 4
enable-incremental: true
incremental-interval: 60000
# 监控配置
monitoring:
enable: true
report-format: json
save-report: true
使用说明
// 手动触发迁移
@RestController
@RequestMapping("/migration")
public class MigrationController {
@PostMapping("/start")
public ApiResponse startMigration() {
// 启动异步迁移任务
CompletableFuture.runAsync(() -> {
migrationManager.executeMigration();
});
return ApiResponse.success("迁移任务已启动");
}
@GetMapping("/progress")
public ApiResponse getProgress() {
return ApiResponse.success(migrationMonitor.generateReport());
}
@PostMapping("/rollback")
public ApiResponse rollback() {
// 回滚操作
return ApiResponse.success("已回滚");
}
}
关键要点
- 安全性:在迁移前做好数据备份
- 一致性:保证数据迁移过程中的一致性
- 性能:使用批量处理提升迁移效率
- 监控:实时监控迁移进度和异常
- 回滚:提供完整的回滚机制
这个案例展示了完整的系统迁移方案,包括数据迁移、服务迁移、监控和配置管理等核心功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播