setName('gift:migration')
->setDescription('送礼数据分表迁移工具')
->addArgument('action', Argument::REQUIRED, '操作类型: init-tables, migrate, progress, verify, clean')
->addOption('month', 'm', Option::VALUE_OPTIONAL, '指定年月,格式: 202401')
->addOption('batch-size', 'b', Option::VALUE_OPTIONAL, '每批迁移数量', 1000)
->addOption('start-id', 's', Option::VALUE_OPTIONAL, '起始ID', 0)
->addOption('months', null, Option::VALUE_OPTIONAL, '创建几个月分表', 12);
}
protected function execute(Input $input, Output $output)
{
$action = $input->getArgument('action');
$month = $input->getOption('month');
$batchSize = $input->getOption('batch-size');
$startId = $input->getOption('start-id');
$months = $input->getOption('months');
Log::info("执行送礼数据迁移命令,动作: {$action}, 月份: {$month}");
switch ($action) {
case 'init-tables':
$this->initTables($output, $months);
break;
case 'migrate':
$this->migrateData($output, $month, $batchSize, $startId);
break;
case 'progress':
$this->showProgress($output);
break;
case 'verify':
$this->verifyData($output, $month);
break;
case 'clean':
$this->cleanOldData($output);
break;
default:
$output->writeln('未知操作类型');
break;
}
}
/**
* 初始化分表
*/
protected function initTables(Output $output, $months)
{
$output->writeln('开始初始化分表...');
$results = GiftTableManager::initTables(null, $months);
$successCount = 0;
$failCount = 0;
foreach ($results as $tableMonth => $success) {
if ($success) {
$output->writeln("创建表 fa_vs_give_gift_{$tableMonth} 成功");
$successCount++;
} else {
$output->writeln("创建表 fa_vs_give_gift_{$tableMonth} 失败");
$failCount++;
}
}
$output->writeln("分表初始化完成,成功: {$successCount}, 失败: {$failCount}");
}
/**
* 迁移数据
*/
protected function migrateData(Output $output, $month, $batchSize, $startId)
{
if ($month) {
// 迁移指定月份
$output->writeln("开始迁移 {$month} 数据...");
$result = GiftDataMigrator::migrateMonthData($month, $batchSize, $startId);
if ($result['success']) {
$output->writeln("{$month} 数据迁移成功");
$output->writeln("迁移总数: " . $result['total']);
$output->writeln("最后ID: " . $result['last_id']);
} else {
$output->writeln("{$month} 数据迁移失败: " . $result['message'] . "");
}
} else {
// 迁移所有数据
$output->writeln('开始迁移所有数据...');
$result = GiftDataMigrator::migrateAllData($batchSize);
if ($result['success']) {
$output->writeln("所有数据迁移成功");
// 显示每个月份的结果
foreach ($result['results'] as $month => $monthResult) {
$status = $monthResult['success'] ? '成功' : '失败';
$output->writeln("{$month}: {$status}, 数量: " . ($monthResult['total'] ?? 0));
}
} else {
$output->writeln("数据迁移失败: " . $result['message'] . "");
}
}
}
/**
* 显示迁移进度
*/
protected function showProgress(Output $output)
{
$progress = GiftDataMigrator::getMigrationProgress();
$output->writeln("数据迁移进度:");
$output->writeln("原始表数据量: " . $progress['total']);
$output->writeln("已迁移数据量: " . $progress['migrated']);
$output->writeln("迁移进度: " . $progress['progress'] . "%");
$output->writeln("剩余数据: " . $progress['remaining']);
if ($progress['total'] > 0 && $progress['migrated'] > 0) {
$output->writeln("迁移进度正常");
} else {
$output->writeln("暂无迁移进度数据");
}
}
/**
* 验证数据
*/
protected function verifyData(Output $output, $month)
{
if (!$month) {
// 验证所有月份
$tables = GiftTableManager::getAllTables();
foreach ($tables as $table) {
$month = substr($table['table_name'], -6);
$this->verifySingleMonth($output, $month);
}
} else {
$this->verifySingleMonth($output, $month);
}
}
/**
* 验证单个月份数据
*/
protected function verifySingleMonth(Output $output, $month)
{
$output->writeln("验证 {$month} 数据一致性...");
$result = GiftDataMigrator::verifyMigration($month);
$output->writeln("原始表数据量: " . $result['source_count']);
$output->writeln("目标表数据量: " . $result['target_count']);
$output->writeln("数据量匹配: " . ($result['count_match'] ? '是' : '否'));
$output->writeln("原始表总价值: " . $result['source_total_price']);
$output->writeln("目标表总价值: " . $result['target_total_price']);
$output->writeln("总价值匹配: " . ($result['price_match'] ? '是' : '否'));
if ($result['count_match'] && $result['price_match']) {
$output->writeln("{$month} 数据验证通过");
} else {
$output->writeln("{$month} 数据验证失败");
}
}
/**
* 清理旧数据(迁移完成后)
*/
protected function cleanOldData(Output $output)
{
$output->writeln("警告:此操作将清理原始表数据,请确认迁移已完成且验证通过!");
$output->writeln("输入 'yes' 继续: ");
$handle = fopen("php://stdin", "r");
$line = fgets($handle);
fclose($handle);
if (trim($line) != 'yes') {
$output->writeln("操作取消");
return;
}
// 备份原始表
$output->writeln("正在备份原始表...");
try {
Db::execute("DROP TABLE IF EXISTS `fa_vs_give_gift_old`");
Db::execute("CREATE TABLE `fa_vs_give_gift_old` LIKE `fa_vs_give_gift`");
Db::execute("INSERT INTO `fa_vs_give_gift_old` SELECT * FROM `fa_vs_give_gift`");
$output->writeln("原始表备份完成");
} catch (\Exception $e) {
$output->writeln("备份原始表失败: " . $e->getMessage() . "");
return;
}
// 清空原始表
$output->writeln("正在清空原始表...");
try {
Db::execute("TRUNCATE TABLE `fa_vs_give_gift`");
$output->writeln("原始表已清空");
} catch (\Exception $e) {
$output->writeln("清空原始表失败: " . $e->getMessage() . "");
}
}
}