Files
yusheng-php/application/common/library/GiftDataMigrator.php
2025-12-30 15:25:58 +08:00

255 lines
8.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// application/common/library/GiftDataMigrator.php
namespace app\common\library;
use think\Db;
use think\Exception;
use think\Log;
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')
->order('createtime', 'asc')
->find();
$lastRecord = Db::name('vs_give_gift')
->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
];
}
}