导读:本期聚焦于小伙伴创作的《C#如何执行SQL删除?最全执行方法与实战要点总结》,敬请观看详情。直接调用SqlCommand执行DELETE语句时,若拼接字符串拼入用户输入,会瞬间埋下SQL注入隐患。正确做法是用参数化查询隔离指令与数据。在C#里,借助ADO.NET的SqlConnection与SqlCommand可完成单条、批量及带条件的删除。事务能保证多条删除要么全成要么全败。本文梳理从基础连接到事务控制、异步删除与Dapper简化写法的完整用法,并给出避免锁表与误删全表的实践建议,帮助你在不同场景下选对方式安全删数。

在C#应用中操作数据库时,删除数据是最常见的写操作之一。不同于查询,删除具备破坏性与不可逆特征,一旦条件写错就可能清掉整张表。因此理解C#执行SQL删除的各类方式、参数化处理与事务控制,是后端开发的基本功。下面从最基础的ADO.NET用法讲起,逐步覆盖批量删除、异步执行以及第三方库方案。

C#如何执行SQL删除?最全执行方法与实战要点总结

一、使用ADO.NET执行基础删除

ADO.NET是.NET原生的数据访问组件,通过SqlConnection和SqlCommand即可完成删除。核心思路是先建立连接,再创建命令对象,把DELETE语句与参数传入,最后调用ExecuteNonQuery获取受影响行数。

下面示例演示删除指定ID的用户记录。注意这里使用@Id参数,而不是把值拼进SQL字符串,这能彻底阻隔SQL注入。即使传入的字符串包含恶意片段,也只会被当作参数值处理。

using System;
using System.Data.SqlClient;

class Demo
{
    static void DeleteUser(int id)
    {
        string connStr = "Server=127.0.0.1;Database=TestDb;User Id=sa;Password=123;";
        using (var conn = new SqlConnection(connStr))
        {
            conn.Open();
            string sql = "DELETE FROM Users WHERE Id = @Id";
            using (var cmd = new SqlCommand(sql, conn))
            {
                cmd.Parameters.AddWithValue("@Id", id);
                int rows = cmd.ExecuteNonQuery();
                Console.WriteLine("删除了" + rows + "行");
            }
        }
    }
}

上述代码用using确保连接与命令对象被释放,避免连接泄漏。ExecuteNonQuery返回的是被删除的行数,若返回0说明没有匹配记录,业务层可据此提示用户数据不存在。

若不使用参数,而写成string sql = "DELETE FROM Users WHERE Id=" + id,当id来自前端输入且被篡改为"1; DROP TABLE Users"时,后果不堪设想。所以参数化不是可选项,而是强制规范。

二、带条件的批量删除与事务

实际业务中常需按状态批量清理数据,例如删除三十天前且已失效的订单。此时仍然使用参数化,只是WHERE条件更复杂。另外,若一次请求要删多张关联表,就必须用事务包裹,防止只删了主表而明细表残留。

事务通过SqlTransaction实现,在conn.BeginTransaction后,把事务对象赋给命令的Transaction属性。只有调用Commit才会真正生效,任何异常时执行Rollback即可回滚。

using System;
using System.Data.SqlClient;

class BatchDemo
{
    static void DeleteOldOrders()
    {
        string connStr = "Server=127.0.0.1;Database=TestDb;User Id=sa;Password=123;";
        using (var conn = new SqlConnection(connStr))
        {
            conn.Open();
            using (var tx = conn.BeginTransaction())
            {
                try
                {
                    string sql = "DELETE FROM OrderDetail WHERE OrderId IN (SELECT Id FROM Orders WHERE Status=@St AND CreateTime<@Limit)";
                    using (var cmd = new SqlCommand(sql, conn, tx))
                    {
                        cmd.Parameters.AddWithValue("@St", 0);
                        cmd.Parameters.AddWithValue("@Limit", DateTime.Now.AddDays(-30));
                        cmd.ExecuteNonQuery();
                    }
                    string sql2 = "DELETE FROM Orders WHERE Status=@St AND CreateTime<@Limit";
                    using (var cmd2 = new SqlCommand(sql2, conn, tx))
                    {
                        cmd2.Parameters.AddWithValue("@St", 0);
                        cmd2.Parameters.AddWithValue("@Limit", DateTime.Now.AddDays(-30));
                        cmd2.ExecuteNonQuery();
                    }
                    tx.Commit();
                }
                catch (Exception ex)
                {
                    tx.Rollback();
                    Console.WriteLine("删除失败:" + ex.Message);
                }
            }
        }
    }
}

上面的代码先删明细再删主表,事务保证两步同生共死。若明细删除成功但主表因外键冲突报错,Rollback会让明细也还原,数据库状态保持一致。

需要提醒的是,大批量删除会锁表并写满日志。生产环境建议分批次删除,比如每次删一千行并短暂休眠,降低对线上读写的影响。

三、异步删除与Dapper简化

在Web接口中,同步删除会占用线程池线程。C#提供了ExecuteNonQueryAsync等异步方法,配合async/await可提升吞吐。另外,Dapper这类轻量ORM能把参数映射和对象转换简化成几行代码。

下面先用原生异步展示,再用Dapper对比。异步版本把Open和Execute都换成Async后缀,并在调用处await,避免阻塞请求线程。

using System;
using System.Data.SqlClient;
using System.Threading.Tasks;

class AsyncDemo
{
    static async Task DeleteUserAsync(int id)
    {
        string connStr = "Server=127.0.0.1;Database=TestDb;User Id=sa;Password=123;";
        using (var conn = new SqlConnection(connStr))
        {
            await conn.OpenAsync();
            string sql = "DELETE FROM Users WHERE Id = @Id";
            using (var cmd = new SqlCommand(sql, conn))
            {
                cmd.Parameters.AddWithValue("@Id", id);
                int rows = await cmd.ExecuteNonQueryAsync();
                Console.WriteLine("异步删除行数:" + rows);
            }
        }
    }
}

Dapper只需一个Execute调用,它内部仍走参数化,不会引入注入风险。对于习惯写POCO对象的团队,可以少写大量样板代码。

using System;
using System.Data.SqlClient;
using Dapper;

class DapperDemo
{
    static void DeleteWithDapper(int id)
    {
        string connStr = "Server=127.0.0.1;Database=TestDb;User Id=sa;Password=123;";
        using (var conn = new SqlConnection(connStr))
        {
            int rows = conn.Execute("DELETE FROM Users WHERE Id = @Id", new { Id = id });
            Console.WriteLine("Dapper删除行数:" + rows);
        }
    }
}

从对比可见,Dapper把连接、命令、参数添加压缩到一行,同时保留参数化安全特性。但在极复杂动态条件删除时,仍建议手写SQL片段拼接参数,或借助Dapper的DynamicParameters灵活传参。

无论用哪种方式,上线前都应在测试库用SELECT验证WHERE命中范围,确认不会误伤数据。必要时先备份再做删除,尤其是没有软删除设计的老系统。

四、常见误区与避坑清单

不少初学者认为DELETE比DROP安全,便在管理后台暴露无条件的删除入口,结果运维点错清空全表。其实DELETE不带WHERE就是全表删除,且会逐行记日志,比TRUNCATE更慢更危险。

另一个误区是滥用AddWithValue导致类型推断偏差,例如传入长整型却被推断为int,使参数匹配失败。对关键字段建议显式指定SqlDbType与尺寸,如cmd.Parameters.Add("@Id", SqlDbType.Int).Value = id。

做法风险建议
字符串拼接SQLSQL注入、删库始终参数化
无WHERE删除全表清空加保护确认或软删除
大事务长删除锁表阻塞分批或低峰执行

最后,对于核心业务数据,推荐引入软删除字段如IsDeleted,用UPDATE替代DELETE,既满足合规审计,也降低误操作成本。真正物理删除只留给日志类或临时表。

掌握上述C#执行SQL删除的多种写法与防护手段后,你就能在控制台、Web API或后台任务中稳妥地清理数据,既高效又不怕踩坑。

C#SQL删除ADO.NET修改时间:2026-08-05 19:06:35

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。