Files
SecMPS/api_sqlsugar/VolPro.Core/DbManager/DbCopy/DbCopyMySql.cs
2026-05-15 23:22:48 +08:00

285 lines
12 KiB
C#
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.
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using VolPro.Core.Extensions;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
namespace VolPro.Core.DbManager.DbCopy
{
/// <summary>
/// MySQL 数据库复制工具类
/// </summary>
public class DbCopyMysql
{
public static WebResponseContent CopyDatabase(ISqlSugarClient db,ISqlSugarClient toDbContext, string sourceDatabase,
string targetDatabase, bool includeData = true)
{
var result = new CopyResult();
var logs = result.Logs;
try
{
// 验证
if (string.IsNullOrWhiteSpace(sourceDatabase))
throw new ArgumentException("源数据库名不能为空");
if (string.IsNullOrWhiteSpace(targetDatabase))
throw new ArgumentException("目标数据库名不能为空");
if (sourceDatabase.Equals(targetDatabase, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("源和目标数据库不能相同");
logs.Add($"[{DateTime.Now:HH:mm:ss}] 开始复制: {sourceDatabase} -> {targetDatabase}");
// 检查源数据库
if (!DbExists(db, sourceDatabase))
throw new Exception($"源数据库 '{sourceDatabase}' 不存在");
// 检查目标数据库
if (DbExists(db, targetDatabase))
throw new Exception($"目标数据库 '{targetDatabase}' 已存在");
// 创建目标数据库
logs.Add($"[{DateTime.Now:HH:mm:ss}] 创建目标数据库...");
CreateDb(db, sourceDatabase, targetDatabase);
// 复制表
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制表...");
CopyTables(db,toDbContext, sourceDatabase, targetDatabase, includeData, result, logs);
// 复制视图
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制视图...");
result.ViewsCount = CopyViews(db,toDbContext, sourceDatabase, targetDatabase, logs);
// 复制存储过程
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制存储过程...");
result.ProceduresCount = CopyRoutines(db, toDbContext, sourceDatabase, targetDatabase, "PROCEDURE", logs);
// 复制函数
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制函数...");
result.FunctionsCount = CopyRoutines(db,toDbContext, sourceDatabase, targetDatabase, "FUNCTION", logs);
// 复制触发器
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制触发器...");
result.TriggersCount = CopyTriggers(db, sourceDatabase, targetDatabase, logs);
result.Success = true;
result.Message = "复制成功";
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✓ 完成! 表:{result.TablesCount} 视图:{result.ViewsCount} " +
$"存储过程:{result.ProceduresCount} 函数:{result.FunctionsCount} 触发器:{result.TriggersCount} " +
$"行数:{result.TotalRowsCopied} 耗时:{result.ElapsedSeconds:F2}秒");
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✗ 错误: {ex.Message}");
}
WebResponseContent webResponse = new WebResponseContent();
webResponse.Status = result.Success;
webResponse.Message = result.Message;
Logger.Info($"mysql创建数据库{logs.Serialize()}");
return webResponse;
}
/// <summary>
/// 获取数据库列表
/// </summary>
public static List<string> GetDatabases(ISqlSugarClient db)
{
var all = db.Ado.SqlQuery<string>("SHOW DATABASES");
var system = new[] { "information_schema", "mysql", "performance_schema", "sys" };
return all.Where(x => !system.Contains(x.ToLower())).ToList();
}
private static bool DbExists(ISqlSugarClient db, string name)
{
return db.Ado.GetInt(
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name",
new { name }) > 0;
}
private static void CreateDb(ISqlSugarClient db, string source, string target)
{
var info = db.Ado.SqlQuerySingle<dynamic>(@"
SELECT DEFAULT_CHARACTER_SET_NAME AS Charset, DEFAULT_COLLATION_NAME AS Collation
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name", new { name = source });
var charset = info?.Charset ?? "utf8mb4";
var collation = info?.Collation ?? "utf8mb4_general_ci";
db.Ado.ExecuteCommand($"CREATE DATABASE `{target}` CHARACTER SET {charset} COLLATE {collation}");
}
private static void CopyTables(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
bool includeData, CopyResult result, List<string> logs)
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var tables = db.Ado.SqlQuery<string>($"USE `{source}`;SHOW TABLES;");
db.Ado.ExecuteCommand($"USE `{target}`");
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 0");
foreach (var table in tables)
{
try
{
// 获取建表语句
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TABLE `{table}`");
var sql = GetValue(row, "Create Table");
if (string.IsNullOrEmpty(sql)) continue;
//创建表
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
result.TablesCount++;
logs.Add($" ✓ {table}");
// 复制数据
if (includeData)
{
var rows = db.Ado.ExecuteCommand(
$"INSERT INTO `{target}`.`{table}` SELECT * FROM `{source}`.`{table}`");
result.TotalRowsCopied += rows;
if (rows > 0) logs.Add($" {rows} 行");
}
}
catch (Exception ex)
{
logs.Add($" ✗ {table}: {ex.Message}");
}
}
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 1");
}
private static int CopyViews(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target, List<string> logs)
{
var views = db.Ado.SqlQuery<string>(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = @db",
new { db = source });
var count = 0;
foreach (var view in views)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE VIEW `{view}`;");
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE VIEW `{view}`;");
var sql = GetValue(row, "Create View");
if (string.IsNullOrEmpty(sql)) continue;
sql = sql.Replace($"`{source}`.", $"`{target}`.");
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {view}");
}
catch (Exception ex)
{
logs.Add($" ✗ {view}: {ex.Message}");
}
}
return count;
}
private static int CopyRoutines(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
string type, List<string> logs)
{
var routines = db.Ado.SqlQuery<string>(
"SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = @db AND ROUTINE_TYPE = @type",
new { db = source, type });
var count = 0;
var key = type == "PROCEDURE" ? "Create Procedure" : "Create Function";
foreach (var routine in routines)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE {type} `{routine}`;");
// var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE {type} `{routine}`;");
var sql = GetValue(row, key);
if (string.IsNullOrEmpty(sql)) continue;
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {routine}");
}
catch (Exception ex)
{
logs.Add($" ✗ {routine}: {ex.Message}");
}
}
return count;
}
private static int CopyTriggers(ISqlSugarClient db, string source, string target, List<string> logs)
{
var triggers = db.Ado.SqlQuery<string>(
"SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = @db",
new { db = source });
var count = 0;
foreach (var trigger in triggers)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TRIGGER `{trigger}`;");
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE TRIGGER `{trigger}`;");
var sql = GetValue(row, "SQL Original Statement");
if (string.IsNullOrEmpty(sql)) continue;
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
db.Ado.ExecuteCommand($"USE `{target}`");
db.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {trigger}");
}
catch (Exception ex)
{
logs.Add($" ✗ {trigger}: {ex.Message}");
}
}
return count;
}
private static string GetValue(dynamic row, string key)
{
if (row == null) return "";
var dict = row as IDictionary<string, object>;
return dict?.ContainsKey(key) == true ? dict[key]?.ToString() ?? "" : "";
}
}
public class CopyResult
{
public bool Success { get; set; }
public string Message { get; set; } = "";
public int TablesCount { get; set; }
public int ViewsCount { get; set; }
public int ProceduresCount { get; set; }
public int FunctionsCount { get; set; }
public int TriggersCount { get; set; }
public long TotalRowsCopied { get; set; }
public double ElapsedSeconds { get; set; }
public List<string> Logs { get; set; } = new();
}
}