分表数据
This commit is contained in:
225
application/common/command/GiftMigration.php
Normal file
225
application/common/command/GiftMigration.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
// application/common/command/GiftMigration.php
|
||||
|
||||
namespace app\common\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\Log;
|
||||
use think\Db;
|
||||
use app\common\library\GiftTableManager;
|
||||
use app\common\library\GiftDataMigrator;
|
||||
|
||||
class GiftMigration extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->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('<error>未知操作类型</error>');
|
||||
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("<info>创建表 fa_vs_give_gift_{$tableMonth} 成功</info>");
|
||||
$successCount++;
|
||||
} else {
|
||||
$output->writeln("<error>创建表 fa_vs_give_gift_{$tableMonth} 失败</error>");
|
||||
$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("<info>{$month} 数据迁移成功</info>");
|
||||
$output->writeln("迁移总数: " . $result['total']);
|
||||
$output->writeln("最后ID: " . $result['last_id']);
|
||||
} else {
|
||||
$output->writeln("<error>{$month} 数据迁移失败: " . $result['message'] . "</error>");
|
||||
}
|
||||
} else {
|
||||
// 迁移所有数据
|
||||
$output->writeln('开始迁移所有数据...');
|
||||
$result = GiftDataMigrator::migrateAllData($batchSize);
|
||||
|
||||
if ($result['success']) {
|
||||
$output->writeln("<info>所有数据迁移成功</info>");
|
||||
|
||||
// 显示每个月份的结果
|
||||
foreach ($result['results'] as $month => $monthResult) {
|
||||
$status = $monthResult['success'] ? '成功' : '失败';
|
||||
$output->writeln("{$month}: {$status}, 数量: " . ($monthResult['total'] ?? 0));
|
||||
}
|
||||
} else {
|
||||
$output->writeln("<error>数据迁移失败: " . $result['message'] . "</error>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示迁移进度
|
||||
*/
|
||||
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("<info>迁移进度正常</info>");
|
||||
} else {
|
||||
$output->writeln("<comment>暂无迁移进度数据</comment>");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
*/
|
||||
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'] ? '<info>是</info>' : '<error>否</error>'));
|
||||
|
||||
$output->writeln("原始表总价值: " . $result['source_total_price']);
|
||||
$output->writeln("目标表总价值: " . $result['target_total_price']);
|
||||
$output->writeln("总价值匹配: " . ($result['price_match'] ? '<info>是</info>' : '<error>否</error>'));
|
||||
|
||||
if ($result['count_match'] && $result['price_match']) {
|
||||
$output->writeln("<info>{$month} 数据验证通过</info>");
|
||||
} else {
|
||||
$output->writeln("<error>{$month} 数据验证失败</error>");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理旧数据(迁移完成后)
|
||||
*/
|
||||
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("<comment>操作取消</comment>");
|
||||
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("<info>原始表备份完成</info>");
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>备份原始表失败: " . $e->getMessage() . "</error>");
|
||||
return;
|
||||
}
|
||||
|
||||
// 清空原始表
|
||||
$output->writeln("正在清空原始表...");
|
||||
try {
|
||||
Db::execute("TRUNCATE TABLE `fa_vs_give_gift`");
|
||||
$output->writeln("<info>原始表已清空</info>");
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>清空原始表失败: " . $e->getMessage() . "</error>");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user