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. 数据安全优先:开启事务保护、使用参数化查询、合理释放连接资源。
相关推荐
阿钱真强道2 小时前
20 极物智能 knx-主机场景对接
linux·运维·服务器
艾莉丝努力练剑2 小时前
【Linux进程(六)】程序地址空间深度实证:从内存布局验证到虚拟化理解的基石
大数据·linux·运维·服务器·人工智能·windows·centos
咕咕嘎嘎10242 小时前
C++仿muduo库onethreadoneloop高并发服务器
服务器·网络·c++
虾..2 小时前
Linux 信号发送和保存
linux·运维·服务器
fengye2071612 小时前
win10 + vs2026 远程调试环境
windows
“抚琴”的人2 小时前
C#上位机状态模式
c#·状态模式
“抚琴”的人2 小时前
C#上位机观察者模式
开发语言·观察者模式·c#·上位机
盛满暮色 风止何安2 小时前
负载均衡的部署模式
运维·服务器·网络·网络安全·负载均衡
程序员洲洲2 小时前
2025年远程控制软件排行榜:安全性能哪家强?ToDesk/TeamViewer/向日葵等对比
服务器·安全·远程控制