sqlconnection打开前须校验连接字符串有效性,executenonquery()返回受影响行数而非布尔值,datareader必须用using确保关闭,参数化查询需避免addwithvalue隐式类型推断风险。

SqlConnection 打开前必须检查连接字符串是否有效
很多运行时异常其实源于 connectionString 格式错误或权限不足,但 new SqlConnection(...) 不会报错,直到调用 Open() 才抛出 SqlException。建议在打开前做最小验证:
- 用
SqlConnectionStringBuilder构建并校验关键字段(DataSource、InitialCatalog、UserID/IntegratedSecurity) - 避免硬编码连接字符串;若从配置读取,先确认
ConfigurationManager.ConnectionStrings["xxx"]不为null - 开发阶段可加一层
try-catch捕获SqlException并输出Number(如 18456 表示登录失败,4060 表示数据库不存在)
SqlCommand.ExecuteNonQuery() 适合 INSERT/UPDATE/DELETE,但要注意返回值含义
ExecuteNonQuery() 返回的是“受影响的行数”,不是成功与否的布尔值。它对 INSERT、UPDATE、DELETE 有效,但对 CREATE TABLE 或 SET NOCOUNT ON 后的语句可能返回 -1。
- 执行单条
INSERT后返回 1,批量插入返回实际插入行数 - 如果 SQL 中含多个语句(如
UPDATE; SELECT @@ROWCOUNT;),默认只取第一个语句影响行数 - 使用
SET NOCOUNT OFF(SQL Server 默认)才能确保返回正确计数;生产环境若开启NOCOUNT,需显式关闭或改用ExecuteScalar()获取@@ROWCOUNT
using (var cmd = new SqlCommand("UPDATE Users SET Name = @name WHERE Id = @id", conn))
{
cmd.Parameters.AddWithValue("@name", "Alice");
cmd.Parameters.AddWithValue("@id", 123);
int rows = cmd.ExecuteNonQuery(); // rows == 1 表示更新成功,0 表示没匹配到记录
}
DataReader 未关闭会导致连接无法释放,必须用 using 或 try-finally
SqlDataReader 是前向只读流,底层绑定着活动的 SqlConnection。只要它没关闭,连接就一直被占用,极易引发“超时”或“连接池已满”错误。
- 永远不要写
reader.Read()后直接 return,必须保证reader.Close()或Dispose() - 推荐用
using块包裹:它会在作用域结束时自动调用Dispose(),即使发生异常 - 注意:不能在
using (var reader = cmd.ExecuteReader())外部访问 reader,也不能把它 return 出去——它生命周期只限于该块内
using (var cmd = new SqlCommand("SELECT Name FROM Users WHERE Active = 1", conn))
{
using (var reader = cmd.ExecuteReader()) // 自动关闭 reader 和关联连接(如果 connection 也在此 using 中)
{
while (reader.Read())
{
Console.WriteLine(reader.GetString(0));
}
} // reader.Dispose() 在这里隐式调用
}
参数化查询防注入是必须的,但 AddWithValue 有隐式类型推断风险
用 AddWithValue 看似方便,但 SQL Server 可能将 null 推断为 int 而非 varchar,导致索引失效或隐式转换。尤其在 WHERE 条件中传 null 时,执行计划可能变差。
- 明确指定类型:用
Parameters.Add("@name", SqlDbType.NVarChar).Value = "Alice" - 对可能为
null的值,显式赋DBNull.Value,而非null - 避免在 LIKE 参数中直接拼接
%:应写成cmd.Parameters.Add("@term", SqlDbType.NVarChar).Value = "%" + userInput + "%",而不是在 SQL 字符串里拼
真正容易被忽略的是:即使用了参数化,如果业务逻辑仍把用户输入拼进 SQL 字符串(比如动态表名、列名、排序字段),照样存在注入风险——这些无法参数化,必须白名单校验。










