C# Mysql 单表父子多层级数据迁移

以下是针对单表父子层级数据迁移的完整解决方案,采用层级遍历方式处理多级嵌套关系:

一、迁移流程图解

graph TD
    A[读取根节点] --> B[插入根节点并记录ID映射]
    B --> C[处理子节点队列]
    C --> D{队列是否为空?}
    D -->|是| E[完成迁移]
    D -->|否| F[取出节点并插入子节点]
    F --> G[更新子节点PID并记录映射]
    G --> C


二、完整实现代码

public class TreeNode
{
    public int OldId { get; set; }
    public int? OldParentId { get; set; }
    public string Data { get; set; }
}

public void MigrateHierarchicalData(string sourceConnStr, string targetConnStr)
{
    // 禁用外键约束
    using (var targetConn = new MySqlConnection(targetConnStr))
    {
        targetConn.Open();
        new MySqlCommand("SET FOREIGN_KEY_CHECKS = 0", targetConn).ExecuteNonQuery();
    }

    // 获取原始数据
    var allNodes = GetSourceData(sourceConnStr);
    
    // 创建ID映射字典
    Dictionary<int, int> idMap = new Dictionary<int, int>();
    Queue<TreeNode> processQueue = new Queue<TreeNode>();

    // 使用事务处理
    using (var targetConn = new MySqlConnection(targetConnStr))
    {
        targetConn.Open();
        using (var transaction = targetConn.BeginTransaction())
        {
            try
            {
                // 第一阶段:插入所有根节点
                var rootNodes = allNodes.Where(n => !n.OldParentId.HasValue).ToList();
                foreach (var node in rootNodes)
                {
                    var newId = InsertNode(node, null, targetConn, transaction);
                    idMap.Add(node.OldId, newId);
                    processQueue.Enqueue(node);
                }

                // 第二阶段:层级遍历处理子节点
                while (processQueue.Count > 0)
                {
                    var current = processQueue.Dequeue();
                    var children = allNodes.Where(n => 
                        n.OldParentId == current.OldId).ToList();

                    foreach (var child in children)
                    {
                        var newId = InsertNode(child, idMap[current.OldId], 
                                            targetConn, transaction);
                        idMap.Add(child.OldId, newId);
                        processQueue.Enqueue(child);
                    }
                }

                transaction.Commit();
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
        }
    }

    // 恢复外键约束
    using (var targetConn = new MySqlConnection(targetConnStr))
    {
        targetConn.Open();
        new MySqlCommand("SET FOREIGN_KEY_CHECKS = 1", targetConn).ExecuteNonQuery();
    }
}

private List<TreeNode> GetSourceData(string connStr)
{
    var nodes = new List<TreeNode>();
    using (var conn = new MySqlConnection(connStr))
    {
        conn.Open();
        var cmd = new MySqlCommand("SELECT id, pid, data FROM hierarchy_table", conn);
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                nodes.Add(new TreeNode
                {
                    OldId = reader.GetInt32(0),
                    OldParentId = reader.IsDBNull(1) ? null : (int?)reader.GetInt32(1),
                    Data = reader.GetString(2)
                });
            }
        }
    }
    return nodes;
}

private int InsertNode(TreeNode node, int? newParentId, 
                     MySqlConnection conn, MySqlTransaction transaction)
{
    var cmd = new MySqlCommand(
        "INSERT INTO hierarchy_table (pid, data) VALUES (@pid, @data); 
         SELECT LAST_INSERT_ID();",
        conn, transaction);

    cmd.Parameters.AddWithValue("@pid", newParentId ?? (object)DBNull.Value);
    cmd.Parameters.AddWithValue("@data", node.Data);
    
    return Convert.ToInt32(cmd.ExecuteScalar());
}


三、关键实现逻辑说明

1、层级遍历算法

使用队列实现广度优先遍历
确保父节点总是先于子节点插入
自动处理任意深度层级关系

2、ID映射维护

idMap字典存储原始ID与新ID对应关系
插入时即时更新映射关系

idMap.Add(child.OldId, newId);

3、事务控制

整个迁移过程在单个事务中完成
支持百万级数据迁移(需调整事务粒度)


四、性能优化方案

1、批量插入优化

// 每次批量插入500条
const int batchSize = 500;
var bulkInsertCmd = new MySqlCommand();
var parameters = new List<MySqlParameter>();

for (int i = 0; i < batchSize; i++)
{
    bulkInsertCmd.CommandText += 
        $"INSERT INTO hierarchy_table (...) VALUES (@pid{i}, @data{i});";
    parameters.Add(new MySqlParameter($"@pid{i}", MySqlDbType.Int32));
    parameters.Add(new MySqlParameter($"@data{i}", MySqlDbType.VarChar));
}
bulkInsertCmd.Parameters.AddRange(parameters.ToArray());

2、内存分页处理

int pageSize = 10000;
for (int page = 0; page < Math.Ceiling(allNodes.Count / (double)pageSize); page++)
{
    var currentPage = allNodes.Skip(page * pageSize).Take(pageSize).ToList();
    // 处理当前分页数据...
}


五、数据验证方法

1、层级完整性检查

WITH RECURSIVE cte AS (
    SELECT id, pid, 1 as level 
    FROM hierarchy_table 
    WHERE pid IS NULL
    UNION ALL
    SELECT t.id, t.pid, cte.level + 1 
    FROM hierarchy_table t
    INNER JOIN cte ON t.pid = cte.id
)
SELECT MAX(level) as max_depth, COUNT(*) as total_nodes 
FROM cte;

2、ID映射验证

// 验证映射完整性
var missingMappings = allNodes
    .Where(n => !idMap.ContainsKey(n.OldId))
    .ToList();

// 验证父子关系
var brokenLinks = allNodes
    .Where(n => n.OldParentId.HasValue && 
               !idMap.ContainsKey(n.OldParentId.Value))
    .ToList();


六、异常处理方案

1、断点续传机制

// 保存迁移进度
File.WriteAllText("progress.log", 
    JsonConvert.SerializeObject(new {
        LastProcessedId = currentId,
        IdMapping = idMap
    }));

// 从断点恢复
if (File.Exists("progress.log"))
{
    var progress = JsonConvert.DeserializeObject(File.ReadAllText("progress.log"));
    // 从上次中断的位置继续...
}

2、并发冲突处理

try
{
    // 数据库操作...
}
catch (MySqlException ex) when (ex.Number == 1213) // 死锁错误代码
{
    Thread.Sleep(new Random().Next(100, 500));
    // 重试操作...
}

        本方案通过层级遍历算法确保父子关系的正确迁移,结合事务控制与批量操作优化,可高效完成包含复杂层级关系的单表数据迁移。建议在正式使用前进行以下验证:

1、使用测试数据验证3层以上嵌套结构

2、模拟中断恢复场景测试断点续传功能

3、使用100万级数据量进行压力测试

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

csdn_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值