在C#开发过程中,和数据库交互时经常需要动态拼接SQL语句,比如根据用户输入的条件筛选数据。如果直接使用字符串拼接,很容易留下SQL注入的安全漏洞,而结合StringBuilder和参数化查询可以很好地解决这个问题。

C#拼接SQL语句的常见方式
普通字符串拼接的问题
最原始的拼接方式是使用string的+运算符,比如下面这段代码:
string userName = "test"; string sql = "SELECT * FROM Users WHERE UserName = '" + userName + "'";
如果用户输入的userName是' OR '1'='1,拼接后的SQL就会变成SELECT * FROM Users WHERE UserName = '' OR '1'='1',会查询出所有用户数据,这就是典型的SQL注入攻击。而且频繁的字符串拼接会产生大量临时对象,影响性能。
使用StringBuilder拼接SQL
StringBuilder是可变字符串类型,拼接时不会产生大量临时对象,更适合动态拼接SQL的场景。基础用法如下:
using System.Text;
string userName = "test";
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.Append("SELECT * FROM Users WHERE 1=1 ");
// 动态添加条件
if (!string.IsNullOrEmpty(userName))
{
sqlBuilder.Append(" AND UserName = '").Append(userName).Append("'");
}
string sql = sqlBuilder.ToString();
这种方式虽然提升了拼接性能,但依然没有解决SQL注入的问题,因为用户输入的内容还是直接拼接进了SQL字符串里。
参数化查询防注入的实现
参数化查询是把SQL语句和参数分开传递,数据库会把参数内容当成纯数据处理,不会解析成SQL指令,从根源上避免注入问题。结合StringBuilder的使用方式如下:
using System.Data.SqlClient;
using System.Text;
string userName = "test";
// 用StringBuilder拼接带参数占位符的SQL
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.Append("SELECT * FROM Users WHERE 1=1 ");
if (!string.IsNullOrEmpty(userName))
{
sqlBuilder.Append(" AND UserName = @UserName");
}
string sql = sqlBuilder.ToString();
// 创建连接和命令对象
using (SqlConnection conn = new SqlConnection("Server=127.0.0.1;Database=TestDB;User Id=sa;Password=123456;"))
{
SqlCommand cmd = new SqlCommand(sql, conn);
// 添加参数,参数值会被安全处理
cmd.Parameters.AddWithValue("@UserName", userName);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
// 处理查询结果
}
}
这里的@UserName是参数占位符,通过Parameters.AddWithValue方法添加参数值,数据库不会把参数值里的特殊字符当成SQL指令解析,即使输入' OR '1'='1也不会生效。
两种方式对比
| 对比项 | 普通字符串拼接 | StringBuilder+参数化 |
|---|---|---|
| 性能 | 差,产生大量临时对象 | 好,减少临时对象生成 |
| 安全性 | 低,存在SQL注入风险 | 高,完全避免注入问题 |
| 适用场景 | 无动态条件、无用户输入的固定SQL | 有动态条件、包含用户输入的SQL拼接 |
注意事项
- 参数占位符的名称要和添加参数时的名称一致,不同数据库的占位符格式可能不同,比如MySQL使用
?作为占位符。 - 不要为了省事直接拼接参数值到SQL字符串里,哪怕输入内容是内部生成的,也可能因为后续逻辑修改引入注入风险。
- 使用完数据库连接、命令对象后要及时释放,推荐使用
using语句自动释放资源。
提示:如果是简单的固定SQL,不需要动态拼接的时候,也可以直接使用参数化查询,不需要用StringBuilder,减少不必要的代码。
C#StringBuilderSQL拼接参数化查询防SQL注入修改时间:2026-06-10 10:06:35