多数据高性能 同步 到本地数据库表里

开发环境

VS2022

net4.5

上位机程序

在 C# .NET Framework 4.5 中,将多个数据同步到本地 SQL Server 数据库表,并实现高性能的 SqlCommand 插入操作,最佳实践是使用 SqlBulkCopy。这是微软提供的专门用于高效批量插入数据的类。

以下是几种不同的实现方式,从最推荐的 SqlBulkCopy 开始:

方法一:使用 SqlBulkCopy (推荐 - 最高性能)

这种方法是处理大量数据插入时最高效的方式。

cs 复制代码
using System;
using System.Data;
using System.Data.SqlClient; // 注意:.NET Framework 4.5 使用 System.Data.SqlClient
using System.Diagnostics;

public class DataSyncService
{
    private readonly string _connectionString;

    public DataSyncService(string connectionString)
    {
        _connectionString = connectionString;
    }

    /// <summary>
    /// 使用 SqlBulkCopy 将数据列表高效地插入到数据库中
    /// </summary>
    /// <typeparam name="T">数据对象的类型</typeparam>
    /// <param name="dataList">要插入的数据列表</param>
    /// <param name="tableName">目标数据库表名</param>
    public void BulkInsert<T>(IList<T> dataList, string tableName) where T : class
    {
        if (dataList == null || !dataList.Any()) return;

        // 1. 将 List<T> 转换为 DataTable
        var dataTable = ConvertToDataTable(dataList);

        // 2. 执行批量插入
        using (var connection = new SqlConnection(_connectionString))
        {
            connection.Open();
            using (var bulkCopy = new SqlBulkCopy(connection))
            {
                bulkCopy.DestinationTableName = tableName;
                
                // 设置超时时间(可选,默认30秒)
                bulkCopy.BulkCopyTimeout = 300; // 5分钟
                
                // 设置批处理大小(可选,默认值为0,表示一次性全部提交)
                // 设置一个合理的批次大小可以减少内存占用和网络压力
                bulkCopy.BatchSize = 10000;

                // 映射列(如果DataTable的列名与数据库表的列名不完全一致,需要手动映射)
                // 例如: bulkCopy.ColumnMappings.Add("Name", "DbNameColumn");
                // 如果列名完全一致,可以省略这一步。

                bulkCopy.WriteToServer(dataTable);
            }
        }
    }

    /// <summary>
    /// 将任意类型的 List 转换为 DataTable
    /// </summary>
    private DataTable ConvertToDataTable<T>(IList<T> data) where T : class
    {
        var properties = TypeDescriptor.GetProperties(typeof(T));
        var table = new DataTable();

        // 添加列
        foreach (PropertyDescriptor prop in properties)
        {
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        }

        // 添加行
        foreach (var item in data)
        {
            var row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
            {
                row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            }
            table.Rows.Add(row);
        }

        return table;
    }
}

// --- 使用示例 ---
class Program
{
    static void Main(string[] args)
    {
        var connectionString = "Server=localhost;Database=TestDB;Trusted_Connection=true;";
        var syncService = new DataSyncService(connectionString);

        // 假设你的数据模型
        var users = new List<User>();
        for (int i = 0; i < 100000; i++)
        {
            users.Add(new User { Id = i, Name = $"User{i}", Email = $"user{i}@example.com" });
        }

        Console.WriteLine($"开始同步 {users.Count} 条记录...");
        var sw = Stopwatch.StartNew();

        // 执行批量插入
        syncService.BulkInsert(users, "Users");

        sw.Stop();
        Console.WriteLine($"同步完成,耗时: {sw.ElapsedMilliseconds} ms");
    }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

方法二:使用事务中的参数化 SqlCommand (适用于中等数量数据或复杂逻辑)

如果数据量不是特别大(例如几千到几万条),或者需要在插入过程中执行复杂的业务逻辑判断,可以使用带事务的 SqlCommand

cs 复制代码
public class DataSyncServiceWithTransaction
{
    private readonly string _connectionString;

    public DataSyncServiceWithTransaction(string connectionString)
    {
        _connectionString = connectionString;
    }

    /// <summary>
    /// 在一个事务中批量执行参数化命令进行插入
    /// </summary>
    /// <param name="dataList">要插入的数据列表</param>
    /// <param name="insertCommandText">INSERT SQL语句</param>
    public void InsertInTransaction(List<User> dataList, string insertCommandText)
    {
        using (var connection = new SqlConnection(_connectionString))
        {
            connection.Open();
            using (var transaction = connection.BeginTransaction())
            {
                try
                {
                    using (var command = new SqlCommand(insertCommandText, connection, transaction))
                    {
                        command.Parameters.Add("@Id", SqlDbType.Int);
                        command.Parameters.Add("@Name", SqlDbType.NVarChar, 255);
                        command.Parameters.Add("@Email", SqlDbType.NVarChar, 255);

                        foreach (var user in dataList)
                        {
                            command.Parameters["@Id"].Value = user.Id;
                            command.Parameters["@Name"].Value = user.Name;
                            command.Parameters["@Email"].Value = user.Email;

                            command.ExecuteNonQuery();
                        }
                    }
                    transaction.Commit();
                    Console.WriteLine("所有数据已成功插入!");
                }
                catch
                {
                    transaction.Rollback();
                    Console.WriteLine("发生错误,事务已回滚。");
                    throw;
                }
            }
        }
    }
}

对比

方法 适用场景 性能 复杂度
SqlBulkCopy 大量数据 (>10k+ 行) 最高 低 (需要转换为 DataTable)
事务中的 SqlCommand 中等数据量或需要逐条处理逻辑 较高
相关推荐
朋友圈自动点赞工具10 分钟前
NAS游戏库自动下载新方案,Questarr部署教程
服务器·数据库·游戏·科技资讯
LadiesAndGentlemen39 分钟前
概览篇:世界模型、空间智能与地理空间智能是什么关系
数据库·人工智能·自然语言处理·开源·aigc
昌原的儿子LEO1 小时前
Linux进程知识点总结
linux·服务器·c语言·数据库
Databend1 小时前
Cluster Key 最佳实践:列怎么选、顺序怎么排与粒度设计
大数据·数据库·sql
三8441 小时前
WordPress REST API 参数校验机制剖析:为什么 author__not_in 无法直接盲注?
服务器·前端·数据库
kobe_OKOK_1 小时前
ubuntu server 打包成一个压缩文件,并且在另一台电脑中解压缩
服务器·数据库·ubuntu
又是重名了1 小时前
集团项目信创改造3 mysql to dm 插入获取主键
数据库·mysql·dameng
zengjuan10051 小时前
[特殊字符]️ 松鼠备份 | 数据库备份方案即将重磅上线!三大模式组合拳,精准守护SQL Server每一笔数据
数据库·sqlserver·数据库备份·全量备份·增量备份·差异备份·日志和事务备份
auspicious航2 小时前
PostgreSQL统计信息:SQL调优的“眼睛”与基石
数据库·sql·postgresql