Files
yusheng-php/application/common/library/GiftDataMigrator.php

257 lines
8.3 KiB
PHP
Raw Permalink Normal View History

2025-12-30 11:37:21 +08:00
<?php
// application/common/library/GiftDataMigrator.php
namespace app\common\library;
use think\Db;
use think\Exception;
2025-12-30 15:25:58 +08:00
use think\Log;
2025-12-30 11:37:21 +08:00
class GiftDataMigrator
{
/**
* 迁移单个月份的数据
* @param string $yearMonth 年月 202401
* @param int $batchSize 每批数量
* @param int $startId 起始ID
* @return array 迁移结果
*/
public static function migrateMonthData($yearMonth, $batchSize = 1000, $startId = 0)
{
// 确保目标表存在
GiftTableManager::createMonthTable($yearMonth);
$targetTable = 'fa_vs_give_gift_' . $yearMonth;
$startTime = strtotime($yearMonth . '01 00:00:00');
$endTime = strtotime(date('Y-m-01', strtotime('+1 month', $startTime)));
$totalMigrated = 0;
$lastId = $startId;
$hasMore = true;
Log::info("开始迁移 {$yearMonth} 数据起始ID: {$startId}");
while ($hasMore) {
try {
// 查询原始表数据
$records = Db::name('vs_give_gift')
->where('id', '>', $lastId)
->where('createtime', '>=', $startTime)
->where('createtime', '<', $endTime)
->order('id', 'asc')
->limit($batchSize)
->select();
if (empty($records)) {
$hasMore = false;
break;
}
// 转换数据格式生成雪花ID
$dataToInsert = [];
foreach ($records as $record) {
$newRecord = [
'id' => Snowflake::generate(),
'user_id' => $record['user_id'] ?? 0,
'gift_id' => $record['gift_id'] ?? 0,
'gift_type' => $record['gift_type'] ?? 1,
'number' => $record['number'] ?? 0,
'gift_user' => $record['gift_user'] ?? 0,
'from_id' => $record['from_id'] ?? 0,
'pit_number' => $record['pit_number'] ?? 0,
'total_price' => $record['total_price'] ?? 0,
'type' => $record['type'] ?? 1,
'from' => $record['from'] ?? 1,
'createtime' => $record['createtime'] ?? time(),
'updatetime' => $record['updatetime'] ?? time(),
];
$dataToInsert[] = $newRecord;
$lastId = $record['id']; // 使用原始表的ID
}
// 批量插入到分表
if (!empty($dataToInsert)) {
Db::table($targetTable)->insertAll($dataToInsert);
$totalMigrated += count($dataToInsert);
Log::info("迁移批次成功: {$yearMonth}, 本批: " . count($dataToInsert) . " 条,总计: {$totalMigrated}");
}
// 防止内存占用过高
unset($records, $dataToInsert);
// 小睡一下防止CPU占用过高
usleep(10000);
} catch (\Exception $e) {
Log::error("迁移 {$yearMonth} 数据失败: " . $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage(),
'total' => $totalMigrated,
'last_id' => $lastId
];
}
}
Log::info("完成迁移 {$yearMonth} 数据,总计: {$totalMigrated}");
return [
'success' => true,
'message' => '迁移完成',
'total' => $totalMigrated,
'last_id' => $lastId
];
}
/**
* 迁移所有历史数据
* @param int $batchSize 每批数量
* @return array
*/
public static function migrateAllData($batchSize = 1000)
{
// 获取所有需要迁移的月份
$firstRecord = Db::name('vs_give_gift')
2025-12-30 17:32:16 +08:00
->where('createtime', '>', 0)
2025-12-30 11:37:21 +08:00
->order('createtime', 'asc')
->find();
$lastRecord = Db::name('vs_give_gift')
2025-12-30 17:32:16 +08:00
->where('createtime', '>', 0)
2025-12-30 11:37:21 +08:00
->order('createtime', 'desc')
->find();
if (!$firstRecord || !$lastRecord) {
return ['success' => true, 'message' => '没有数据需要迁移'];
}
$startMonth = date('Ym', $firstRecord['createtime']);
$endMonth = date('Ym', $lastRecord['createtime']);
// 生成月份列表
$months = self::generateMonthRange($startMonth, $endMonth);
Log::info("开始迁移数据,月份范围: {$startMonth}{$endMonth},共 " . count($months) . " 个月");
$results = [];
foreach ($months as $month) {
Log::info("开始迁移 {$month} 数据");
$result = self::migrateMonthData($month, $batchSize);
$results[$month] = $result;
if (!$result['success']) {
Log::error("迁移 {$month} 数据失败,停止迁移");
break;
}
Log::info("完成迁移 {$month} 数据,共 {$result['total']}");
}
return [
'success' => true,
'message' => '所有数据迁移完成',
'results' => $results
];
}
/**
* 生成月份范围
* @param string $startMonth 202401
* @param string $endMonth 202412
* @return array
*/
private static function generateMonthRange($startMonth, $endMonth)
{
$start = new \DateTime($startMonth . '01');
$end = new \DateTime($endMonth . '01');
$months = [];
while ($start <= $end) {
$months[] = $start->format('Ym');
$start->modify('+1 month');
}
return $months;
}
/**
* 获取迁移进度
* @return array
*/
public static function getMigrationProgress()
{
// 查询原始表数据量
$totalCount = Db::name('vs_give_gift')->count();
// 查询已迁移的数据量
$migratedCount = 0;
$tables = GiftTableManager::getAllTables();
foreach ($tables as $tableInfo) {
try {
$count = Db::table($tableInfo['table_name'])->count();
$migratedCount += $count;
} catch (\Exception $e) {
// 表可能不存在,跳过
}
}
$progress = $totalCount > 0 ? round($migratedCount / $totalCount * 100, 2) : 0;
return [
'total' => $totalCount,
'migrated' => $migratedCount,
'progress' => $progress,
'remaining' => $totalCount - $migratedCount
];
}
/**
* 验证迁移数据一致性
* @param string $yearMonth 年月
* @return array
*/
public static function verifyMigration($yearMonth)
{
$startTime = strtotime($yearMonth . '01 00:00:00');
$endTime = strtotime(date('Y-m-01', strtotime('+1 month', $startTime)));
// 原始表数据量
$sourceCount = Db::name('vs_give_gift')
->where('createtime', '>=', $startTime)
->where('createtime', '<', $endTime)
->count();
// 目标表数据量
$targetTable = 'fa_vs_give_gift_' . $yearMonth;
$targetCount = 0;
try {
$targetCount = Db::table($targetTable)->count();
} catch (\Exception $e) {
Log::error("验证迁移数据失败,目标表不存在: " . $targetTable);
}
// 比较总价值
$sourceTotalPrice = Db::name('vs_give_gift')
->where('createtime', '>=', $startTime)
->where('createtime', '<', $endTime)
->sum('total_price');
$targetTotalPrice = 0;
try {
$targetTotalPrice = Db::table($targetTable)->sum('total_price');
} catch (\Exception $e) {
// 表可能不存在
}
return [
'source_count' => $sourceCount,
'target_count' => $targetCount,
'count_match' => $sourceCount == $targetCount,
'source_total_price' => $sourceTotalPrice,
'target_total_price' => $targetTotalPrice,
'price_match' => abs(floatval($sourceTotalPrice) - floatval($targetTotalPrice)) < 0.01
];
}
}