You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

从C#向SQL Server快速插入记录及多表单事务删插操作咨询

从C#向SQL Server插入记录的最快方式及多表事务操作实现

一、最快插入方式:SqlBulkCopy

毫无疑问,SqlBulkCopy是C#里向SQL Server批量插数据的最优解,它专门针对批量数据传输做了优化,比循环跑单条INSERT语句快好几个量级——核心是直接把DataTable、DataReader或者强类型集合的数据批量写入数据库,大幅减少了网络往返的开销。

给你个简单示例(假设你有个User类对应数据库表):

using (var connection = new SqlConnection("你的数据库连接字符串"))
{
    connection.Open();
    
    // 准备插入数据,这里用DataTable举例,也可以用自定义DataReader
    var dataTable = new DataTable();
    dataTable.Columns.Add("Id", typeof(int));
    dataTable.Columns.Add("Name", typeof(string));
    
    // 填充100条测试数据
    for (int i = 0; i < 100; i++)
    {
        dataTable.Rows.Add(i, $"用户_{i}");
    }
    
    using (var bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "Users"; // 目标表名
        // 如果DataTable列名和数据库表列名完全一致,这步映射可以省略
        bulkCopy.ColumnMappings.Add("Id", "Id");
        bulkCopy.ColumnMappings.Add("Name", "UserName");
        
        bulkCopy.WriteToServer(dataTable);
    }
}

如果你的数据是强类型集合,还可以用FastMember这类工具快速把IEnumerable<T>转成DataReader,省去手动构建DataTable的麻烦,性能还能再提一截。

二、单事务内完成5张表的删数+插入操作

要让所有操作要么全成要么全滚,关键是用SqlTransaction把所有删除、插入步骤包起来。结合SqlBulkCopy的实现步骤如下:

  1. 打开数据库连接,启动事务;
  2. 逐个表执行DELETE清空数据;
  3. 逐个表执行批量插入;
  4. 所有操作无异常就提交事务,出问题就回滚。

示例代码如下:

string connectionString = "你的数据库连接字符串";
// 假设要操作的5张表名
List<string> targetTables = new List<string> { "TableA", "TableB", "TableC", "TableD", "TableE" };

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();
    // 开启事务
    using (var transaction = connection.BeginTransaction())
    {
        try
        {
            foreach (var tableName in targetTables)
            {
                // 第一步:清空当前表数据
                string deleteSql = $"DELETE FROM {tableName}";
                using (var deleteCmd = new SqlCommand(deleteSql, connection, transaction))
                {
                    deleteCmd.ExecuteNonQuery();
                }

                // 第二步:批量插入100条数据到当前表
                // 这里用自定义方法生成对应表的DataTable,实际项目里可以根据业务逻辑生成数据
                var tableData = GenerateTableData(tableName);
                
                using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
                {
                    bulkCopy.DestinationTableName = tableName;
                    // 列名一致的话不用手动映射,否则添加ColumnMappings
                    bulkCopy.WriteToServer(tableData);
                }
            }

            // 所有操作成功,提交事务
            transaction.Commit();
            Console.WriteLine("所有表的清空和插入操作已完成!");
        }
        catch (Exception ex)
        {
            // 出错就回滚所有操作
            transaction.Rollback();
            Console.WriteLine($"操作失败,已回滚:{ex.Message}");
            throw; // 可以根据业务需求决定是否抛出异常
        }
    }
}

// 辅助方法:根据表名生成对应结构的DataTable(示例)
private static DataTable GenerateTableData(string tableName)
{
    var dt = new DataTable();
    // 根据不同表名定义对应列,要和数据库表结构匹配
    switch (tableName)
    {
        case "TableA":
            dt.Columns.Add("Id", typeof(int));
            dt.Columns.Add("Content", typeof(string));
            break;
        case "TableB":
            dt.Columns.Add("ProductId", typeof(int));
            dt.Columns.Add("Price", typeof(decimal));
            break;
        // 其他表的列定义...
    }
    
    // 填充100条测试数据
    for (int i = 0; i < 100; i++)
    {
        var row = dt.NewRow();
        if (tableName == "TableA")
        {
            row["Id"] = i;
            row["Content"] = $"测试内容_{i}";
        }
        else if (tableName == "TableB")
        {
            row["ProductId"] = i;
            row["Price"] = i * 2.5m;
        }
        // 其他表的数据填充逻辑...
        dt.Rows.Add(row);
    }
    return dt;
}

几点注意事项:

  • 确保连接字符串开启了连接池(默认是开的),避免频繁创建连接的开销;
  • 如果表有主键或唯一索引,插入前要保证数据不会冲突;
  • 批量插入时如果表有触发器,可能拖慢性能,必要时可以临时禁用触发器(操作完再开启);
  • 这个场景下事务范围不大,不会超时,但如果是超大量数据,要记得调整事务超时时间。

内容的提问来源于stack exchange,提问作者Syed Qayyum

火山引擎 最新活动