|
|
@@ -4,6 +4,7 @@ namespace App\Module\Cleanup\Logics;
|
|
|
|
|
|
use App\Module\Cleanup\Models\CleanupBackup;
|
|
|
use App\Module\Cleanup\Models\CleanupBackupFile;
|
|
|
+use App\Module\Cleanup\Models\CleanupSqlBackup;
|
|
|
use App\Module\Cleanup\Models\CleanupPlan;
|
|
|
use App\Module\Cleanup\Models\CleanupTask;
|
|
|
use App\Module\Cleanup\Enums\BACKUP_TYPE;
|
|
|
@@ -221,6 +222,11 @@ class BackupLogic
|
|
|
private static function backupTable(CleanupBackup $backup, string $tableName, BACKUP_TYPE $backupType, COMPRESSION_TYPE $compressionType): array
|
|
|
{
|
|
|
try {
|
|
|
+ // 数据库备份类型直接存储到数据库
|
|
|
+ if ($backupType === BACKUP_TYPE::DATABASE) {
|
|
|
+ return static::backupTableToDatabase($backup, $tableName);
|
|
|
+ }
|
|
|
+
|
|
|
// 生成备份文件名
|
|
|
$fileName = static::generateBackupFileName($backup, $tableName, $backupType);
|
|
|
$filePath = "cleanup/backups/{$backup->id}/{$fileName}";
|
|
|
@@ -357,6 +363,116 @@ class BackupLogic
|
|
|
return $csv;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 备份表到数据库
|
|
|
+ *
|
|
|
+ * @param CleanupBackup $backup 备份记录
|
|
|
+ * @param string $tableName 表名
|
|
|
+ * @return array 备份结果
|
|
|
+ */
|
|
|
+ private static function backupTableToDatabase(CleanupBackup $backup, string $tableName): array
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 获取表数据
|
|
|
+ $records = DB::table($tableName)->get();
|
|
|
+
|
|
|
+ if ($records->isEmpty()) {
|
|
|
+ // 即使没有数据也创建记录,记录表结构
|
|
|
+ $sqlContent = "-- 表 {$tableName} 的数据备份\n";
|
|
|
+ $sqlContent .= "-- 备份时间: " . now()->toDateTimeString() . "\n";
|
|
|
+ $sqlContent .= "-- 该表无数据记录\n\n";
|
|
|
+
|
|
|
+ // 获取表结构
|
|
|
+ $createTable = DB::select("SHOW CREATE TABLE `{$tableName}`")[0];
|
|
|
+ $sqlContent .= $createTable->{'Create Table'} . ";\n";
|
|
|
+
|
|
|
+ $recordsCount = 0;
|
|
|
+ } else {
|
|
|
+ // 生成INSERT语句
|
|
|
+ $sqlContent = static::generateInsertStatements($tableName, $records);
|
|
|
+ $recordsCount = $records->count();
|
|
|
+ }
|
|
|
+
|
|
|
+ $contentSize = strlen($sqlContent);
|
|
|
+ $contentHash = hash('sha256', $sqlContent);
|
|
|
+
|
|
|
+ // 保存到数据库
|
|
|
+ CleanupSqlBackup::create([
|
|
|
+ 'backup_id' => $backup->id,
|
|
|
+ 'table_name' => $tableName,
|
|
|
+ 'sql_content' => $sqlContent,
|
|
|
+ 'records_count' => $recordsCount,
|
|
|
+ 'content_size' => $contentSize,
|
|
|
+ 'content_hash' => $contentHash,
|
|
|
+ 'backup_conditions' => null, // 暂时不支持条件备份
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'success' => true,
|
|
|
+ 'message' => "表 {$tableName} 数据库备份成功",
|
|
|
+ 'file_size' => $contentSize, // 用内容大小代替文件大小
|
|
|
+ 'records_count' => $recordsCount,
|
|
|
+ ];
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return [
|
|
|
+ 'success' => false,
|
|
|
+ 'message' => $e->getMessage(),
|
|
|
+ 'file_size' => 0,
|
|
|
+ 'records_count' => 0,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成INSERT语句
|
|
|
+ *
|
|
|
+ * @param string $tableName 表名
|
|
|
+ * @param \Illuminate\Support\Collection $records 记录集合
|
|
|
+ * @return string SQL内容
|
|
|
+ */
|
|
|
+ private static function generateInsertStatements(string $tableName, $records): string
|
|
|
+ {
|
|
|
+ $sql = "-- 表 {$tableName} 的数据备份\n";
|
|
|
+ $sql .= "-- 备份时间: " . now()->toDateTimeString() . "\n";
|
|
|
+ $sql .= "-- 记录数量: " . $records->count() . "\n\n";
|
|
|
+
|
|
|
+ // 获取表结构
|
|
|
+ $createTable = DB::select("SHOW CREATE TABLE `{$tableName}`")[0];
|
|
|
+ $sql .= $createTable->{'Create Table'} . ";\n\n";
|
|
|
+
|
|
|
+ // 生成INSERT语句
|
|
|
+ if ($records->isNotEmpty()) {
|
|
|
+ $sql .= "-- 数据插入\n";
|
|
|
+
|
|
|
+ // 获取字段名
|
|
|
+ $firstRecord = (array) $records->first();
|
|
|
+ $columns = array_keys($firstRecord);
|
|
|
+ $columnList = '`' . implode('`, `', $columns) . '`';
|
|
|
+
|
|
|
+ $sql .= "INSERT INTO `{$tableName}` ({$columnList}) VALUES\n";
|
|
|
+
|
|
|
+ $values = [];
|
|
|
+ foreach ($records as $record) {
|
|
|
+ $recordArray = (array) $record;
|
|
|
+ $escapedValues = array_map(function ($value) {
|
|
|
+ if ($value === null) {
|
|
|
+ return 'NULL';
|
|
|
+ } elseif (is_numeric($value)) {
|
|
|
+ return $value;
|
|
|
+ } else {
|
|
|
+ return "'" . addslashes($value) . "'";
|
|
|
+ }
|
|
|
+ }, $recordArray);
|
|
|
+ $values[] = '(' . implode(', ', $escapedValues) . ')';
|
|
|
+ }
|
|
|
+
|
|
|
+ $sql .= implode(",\n", $values) . ";\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ return $sql;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 压缩内容
|
|
|
*
|
|
|
@@ -518,7 +634,7 @@ class BackupLogic
|
|
|
try {
|
|
|
DB::beginTransaction();
|
|
|
|
|
|
- $backup = CleanupBackup::with('files')->findOrFail($backupId);
|
|
|
+ $backup = CleanupBackup::with(['files', 'sqlBackups'])->findOrFail($backupId);
|
|
|
|
|
|
// 删除备份文件
|
|
|
foreach ($backup->files as $file) {
|
|
|
@@ -537,6 +653,9 @@ class BackupLogic
|
|
|
// 删除备份文件记录
|
|
|
$backup->files()->delete();
|
|
|
|
|
|
+ // 删除SQL备份记录
|
|
|
+ $backup->sqlBackups()->delete();
|
|
|
+
|
|
|
// 删除备份记录
|
|
|
$backup->delete();
|
|
|
|