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() . ""); } } }