C# 语言 SQL Server 批量更新

C# 操作 SQL Server 批量更新 完整指南

你需要在 C# 中实现 SQL Server 的批量更新功能,不同数据量场景对应不同最优方案(小数据量简洁高效、大数据量高性能低损耗),下面详细讲解每种方案的实现代码、适用场景及注意事项。

一、 小数据量批量更新(1000 条以内,简洁高效)

适用于更新数据量较少(如几百条)的场景,实现简单、无需额外依赖,核心分为「拼接 SQL 语句」和「参数化 SQL(推荐,防注入)」两种方式。

方案 1:参数化 SQL 拼接(防 SQL 注入,推荐)

通过拼接带参数的 UPDATE 语句,批量执行更新,兼顾简洁性和安全性,避免 SQL 注入风险。

实现代码

csharp

运行

复制代码
using System;
using System.Data.SqlClient;

namespace SqlServerBatchUpdate
{
    class SmallDataBatchUpdate
    {
        // 数据库连接字符串(根据你的实际环境修改)
        private static readonly string _connectionString = "Data Source=你的服务器名;Initial Catalog=你的数据库名;User ID=你的用户名;Password=你的密码;";

        /// <summary>
        /// 批量更新员工薪资(小数据量)
        /// </summary>
        public static void BatchUpdateEmployeeSalary()
        {
            // 模拟需要更新的数据(实际可从业务逻辑中获取)
            var updateList = new List<Employee>()
            {
                new Employee { EmployeeID = 1, Salary = 5500 },
                new Employee { EmployeeID = 2, Salary = 6600 },
                new Employee { EmployeeID = 3, Salary = 7700 }
            };

            // 拼接参数化SQL语句
            var sqlBuilder = new System.Text.StringBuilder();
            var sqlParameters = new List<SqlParameter>();

            for (int i = 0; i < updateList.Count; i++)
            {
                var emp = updateList[i];
                // 定义唯一参数名,避免冲突
                string paramIdName = $"@EmpID{i}";
                string paramSalaryName = $"@EmpSalary{i}";

                // 拼接UPDATE语句(每条数据对应一个UPDATE,或用CASE WHEN优化)
                sqlBuilder.AppendLine($"UPDATE Employee SET Salary = {paramSalaryName} WHERE EmployeeID = {paramIdName};");

                // 添加参数
                sqlParameters.Add(new SqlParameter(paramIdName, emp.EmployeeID));
                sqlParameters.Add(new SqlParameter(paramSalaryName, emp.Salary));
            }

            try
            {
                using (SqlConnection conn = new SqlConnection(_connectionString))
                {
                    conn.Open();
                    using (SqlCommand cmd = new SqlCommand(sqlBuilder.ToString(), conn))
                    {
                        // 添加所有参数
                        cmd.Parameters.AddRange(sqlParameters.ToArray());
                        // 执行批量更新
                        int affectedRows = cmd.ExecuteNonQuery();
                        Console.WriteLine($"成功更新 {affectedRows} 条记录");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"批量更新失败:{ex.Message}");
            }
        }
    }

    // 员工实体类
    public class Employee
    {
        public int EmployeeID { get; set; }
        public decimal Salary { get; set; }
        public string EmployeeName { get; set; }
        public string Department { get; set; }
    }
}
优化:CASE WHEN 减少 SQL 语句数

上述代码每条数据对应一个 UPDATE,可通过 CASE WHEN 优化为单条 UPDATE,提升执行效率:

csharp

运行

复制代码
public static void BatchUpdateEmployeeSalaryWithCaseWhen()
{
    var updateList = new List<Employee>()
    {
        new Employee { EmployeeID = 1, Salary = 5500 },
        new Employee { EmployeeID = 2, Salary = 6600 },
        new Employee { EmployeeID = 3, Salary = 7700 }
    };

    var caseBuilder = new System.Text.StringBuilder();
    var idList = new List<int>();
    var sqlParameters = new List<SqlParameter>();

    // 拼接CASE WHEN语句
    caseBuilder.Append("UPDATE Employee SET Salary = CASE EmployeeID ");
    for (int i = 0; i < updateList.Count; i++)
    {
        var emp = updateList[i];
        string paramIdName = $"@EmpID{i}";
        string paramSalaryName = $"@EmpSalary{i}";

        caseBuilder.AppendLine($"WHEN {paramIdName} THEN {paramSalaryName} ");
        sqlParameters.Add(new SqlParameter(paramIdName, emp.EmployeeID));
        sqlParameters.Add(new SqlParameter(paramSalaryName, emp.Salary));
        idList.Add(emp.EmployeeID);
    }
    caseBuilder.Append("END ");
    // 拼接WHERE条件,限定更新范围
    caseBuilder.Append("WHERE EmployeeID IN (");
    caseBuilder.Append(string.Join(",", idList));
    caseBuilder.Append(");");

    try
    {
        using (SqlConnection conn = new SqlConnection(_connectionString))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(caseBuilder.ToString(), conn))
            {
                cmd.Parameters.AddRange(sqlParameters.ToArray());
                int affectedRows = cmd.ExecuteNonQuery();
                Console.WriteLine($"成功更新 {affectedRows} 条记录");
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"批量更新失败:{ex.Message}");
    }
}

方案 2:循环单条更新(最简单,不推荐大数据量)

逐行遍历数据,执行单条 UPDATE 语句,实现最简单,但性能较差(多次数据库连接 / 交互),仅适用于极少数据(几十条以内)。

实现代码

csharp

运行

复制代码
public static void LoopSingleUpdate()
{
    var updateList = new List<Employee>()
    {
        new Employee { EmployeeID = 1, Salary = 5500 },
        new Employee { EmployeeID = 2, Salary = 6600 }
    };

    string sql = "UPDATE Employee SET Salary = @Salary WHERE EmployeeID = @EmployeeID;";

    try
    {
        using (SqlConnection conn = new SqlConnection(_connectionString))
        {
            conn.Open();
            foreach (var emp in updateList)
            {
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    cmd.Parameters.AddWithValue("@Salary", emp.Salary);
                    cmd.Parameters.AddWithValue("@EmployeeID", emp.EmployeeID);
                    cmd.ExecuteNonQuery();
                }
            }
            Console.WriteLine("全部更新完成");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"更新失败:{ex.Message}");
    }
}

二、 大数据量批量更新(1000 条以上,高性能)

当更新数据量较大(如 1 万、10 万甚至百万级)时,上述小数据量方案会出现性能瓶颈(多次交互、事务日志暴涨),推荐以下两种高性能方案。

方案 1:使用 SqlBulkCopy + 临时表(最优推荐,超高效率)

核心思路:

  1. 将需要更新的数据先通过 SqlBulkCopy 批量插入 SQL Server 临时表;
  2. 通过 JOIN 语法,将临时表与目标表关联,执行批量更新;
  3. 删除临时表(可选,自动临时表会自动销毁)。

该方案最大限度减少数据库交互,利用 SqlBulkCopy 的高性能批量写入能力,是大数据量更新的首选。

实现代码

csharp

运行

复制代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;

namespace SqlServerBatchUpdate
{
    class BigDataBatchUpdate
    {
        private static readonly string _connectionString = "Data Source=你的服务器名;Initial Catalog=你的数据库名;User ID=你的用户名;Password=你的密码;";

        /// <summary>
        /// 大数据量批量更新(SqlBulkCopy + 临时表)
        /// </summary>
        public static void BatchUpdateWithBulkCopy()
        {
            // 模拟10000条需要更新的数据(实际可从业务中获取)
            var updateList = new List<Employee>();
            for (int i = 1; i <= 10000; i++)
            {
                updateList.Add(new Employee { EmployeeID = i, Salary = 5000 + i * 10 });
            }

            // 1. 将List转换为DataTable(SqlBulkCopy支持DataTable入参)
            DataTable tempDt = ConvertListToDataTable(updateList);

            try
            {
                using (SqlConnection conn = new SqlConnection(_connectionString))
                {
                    conn.Open();
                    // 开启事务,确保操作原子性
                    using (SqlTransaction tran = conn.BeginTransaction())
                    {
                        try
                        {
                            // 2. 创建临时表(#开头为局部临时表,仅当前连接可见)
                            string createTempTableSql = @"
                                CREATE TABLE #TempEmployee (
                                    EmployeeID INT PRIMARY KEY,
                                    Salary DECIMAL(18, 2) NOT NULL
                                );";
                            using (SqlCommand cmd = new SqlCommand(createTempTableSql, conn, tran))
                            {
                                cmd.ExecuteNonQuery();
                            }

                            // 3. SqlBulkCopy 批量插入临时表
                            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran))
                            {
                                bulkCopy.DestinationTableName = "#TempEmployee"; // 目标临时表名
                                bulkCopy.BatchSize = 1000; // 每批次插入1000条
                                bulkCopy.BulkCopyTimeout = 30; // 超时时间30秒

                                // 映射DataTable列与临时表列(列名一致可省略,建议显式映射)
                                bulkCopy.ColumnMappings.Add("EmployeeID", "EmployeeID");
                                bulkCopy.ColumnMappings.Add("Salary", "Salary");

                                // 执行批量插入
                                bulkCopy.WriteToServer(tempDt);
                            }

                            // 4. 关联临时表与目标表,执行批量更新
                            string batchUpdateSql = @"
                                UPDATE E
                                SET E.Salary = T.Salary,
                                    E.UpdateTime = GETDATE()
                                FROM Employee E
                                INNER JOIN #TempEmployee T
                                ON E.EmployeeID = T.EmployeeID;";
                            using (SqlCommand cmd = new SqlCommand(batchUpdateSql, conn, tran))
                            {
                                int affectedRows = cmd.ExecuteNonQuery();
                                Console.WriteLine($"成功更新 {affectedRows} 条记录");
                            }

                            // 5. 删除临时表(可选,局部临时表连接关闭后自动销毁)
                            string dropTempTableSql = "DROP TABLE #TempEmployee;";
                            using (SqlCommand cmd = new SqlCommand(dropTempTableSql, conn, tran))
                            {
                                cmd.ExecuteNonQuery();
                            }

                            // 提交事务
                            tran.Commit();
                        }
                        catch (Exception ex)
                        {
                            // 出错回滚事务
                            tran.Rollback();
                            Console.WriteLine($"批量更新失败:{ex.Message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"数据库连接失败:{ex.Message}");
            }
        }

        /// <summary>
        /// List转DataTable(通用方法)
        /// </summary>
        private static DataTable ConvertListToDataTable<T>(List<T> list)
        {
            DataTable dt = new DataTable();
            var properties = typeof(T).GetProperties();

            // 添加DataTable列
            foreach (var prop in properties)
            {
                dt.Columns.Add(prop.Name, prop.PropertyType);
            }

            // 填充DataTable数据
            foreach (var item in list)
            {
                DataRow row = dt.NewRow();
                foreach (var prop in properties)
                {
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                }
                dt.Rows.Add(row);
            }

            return dt;
        }
    }
}

方案 2:使用 Dapper 框架(简洁高效,第三方库)

Dapper 是轻量级 ORM 框架,简化数据库操作,支持批量更新,通过拼接参数化 SQL 或使用 Execute 方法批量执行,兼顾简洁性和性能,需先安装 Dapper 包。

步骤 1:安装 Dapper 包

通过 NuGet 安装:Install-Package Dapperdotnet add package Dapper

实现代码

csharp

运行

复制代码
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Dapper;

namespace SqlServerBatchUpdate
{
    class DapperBatchUpdate
    {
        private static readonly string _connectionString = "Data Source=你的服务器名;Initial Catalog=你的数据库名;User ID=你的用户名;Password=你的密码;";

        /// <summary>
        /// Dapper 批量更新
        /// </summary>
        public static void BatchUpdateWithDapper()
        {
            var updateList = new List<Employee>()
            {
                new Employee { EmployeeID = 1, Salary = 5500 },
                new Employee { EmployeeID = 2, Salary = 6600 },
                new Employee { EmployeeID = 3, Salary = 7700 }
            };

            try
            {
                using (SqlConnection conn = new SqlConnection(_connectionString))
                {
                    conn.Open();
                    // 批量执行更新(Dapper自动处理参数)
                    string sql = "UPDATE Employee SET Salary = @Salary WHERE EmployeeID = @EmployeeID;";
                    int affectedRows = conn.Execute(sql, updateList);
                    Console.WriteLine($"成功更新 {affectedRows} 条记录");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Dapper批量更新失败:{ex.Message}");
            }
        }
    }
}

三、 关键注意事项(避坑指南)

  1. 防 SQL 注入 :始终使用「参数化 SQL」(避免直接拼接字符串),无论是原生 ADO.NET 还是 Dapper,参数化查询是防止 SQL 注入的核心。
  2. 事务保护 :批量更新属于关键操作,建议开启事务(SqlTransaction),确保所有更新要么全部成功,要么全部回滚,避免数据不一致。
  3. 连接释放 :使用 using 语句包裹 SqlConnectionSqlCommand 等对象,自动释放数据库连接资源,避免连接泄露。
  4. 批量大小控制 :使用 SqlBulkCopy 时,合理设置 BatchSize(建议 1000~5000),过大可能占用过多内存,过小会降低效率。
  5. 索引优化 :目标表的关联字段(如 EmployeeID)建议建立主键或索引,提升 JOIN 操作和 WHERE 筛选的效率。
  6. 超时设置 :大数据量更新时,适当调整 CommandTimeout(默认 30 秒),避免因执行时间过长导致超时。

总结

  1. 小数据量(<1000 条) :优先使用「参数化 SQL + CASE WHEN」(原生 ADO.NET)或 Dapper,简洁高效。
  2. 大数据量(≥1000 条):首选「SqlBulkCopy + 临时表」,性能最优,最大限度减少数据库交互。
  3. 开发效率优先:使用 Dapper 框架,简化代码编写,兼顾性能和可读性。
  4. 数据安全优先:开启事务保护、使用参数化查询、合理释放连接资源。
相关推荐
晚风吹长发14 分钟前
初步了解Linux中的动静态库及其制作和使用
linux·运维·服务器·数据结构·c++·后端·算法
Le_ee27 分钟前
dc4打靶报告
运维·服务器·网络
Knight_AL30 分钟前
用 JOL 验证 synchronized 的锁升级过程(偏向锁 → 轻量级锁 → 重量级锁)
开发语言·jvm·c#
抠头专注python环境配置32 分钟前
解决Windows安装PythonOCC报错:从“No module named ‘OCC’ ”到一键成功
人工智能·windows·python·3d·cad·pythonocc
江沉晚呤时1 小时前
从零实现 C# 插件系统:轻松扩展应用功能
java·开发语言·microsoft·c#
4t4run1 小时前
28、Linux 系统定时任务
linux·运维·服务器
我只有一台windows电脑2 小时前
西门子S7通讯(三)
c#
cui__OaO2 小时前
Linux驱动--基于驱动设备分离的按键中断驱动
linux·运维·服务器·嵌入式
C++实习生2 小时前
Visual Studio Express 2015 for Windows Desktop 中文学习版
windows·express·visual studio
csdn_aspnet2 小时前
Windows 11 临时文件夹架构深度解析
windows·临时文件