C#.NET Core 5项目SQL Server连接循环数百次后冻结如何解决
问题修复与代码优化方案
已排查到的核心问题
- SQL语法错误:SELECT子句中
group_country_code字段后多了多余的逗号,会直接导致SQL执行失败,触发异常后返回空列表 - 对象引用错误:循环中反复修改同一个传入的
Contract实例属性再添加到列表,最终列表内所有元素都是同一个对象的引用,属性值为最后一次循环的结果,外部修改该对象时会出现全列表属性同步变更,看起来像返回值为空/null - SQL注入风险:直接拼接SQL字符串,若
Contract.Number含特殊字符(如单引号)会触发SQL语法错误,也存在被注入攻击的风险 - 空值未处理:数据库字段为
DBNull时直接调用ToString()会抛出异常,被catch捕获后方法直接返回空列表 - 不必要的性能开销:每次调用方法都重新实例化
SqlConnectionStringBuilder,无意义的重复初始化会增加性能消耗 - 冗余的连接关闭操作:
using块会在离开作用域时自动释放连接,手动调用Close()反而可能在异常场景下出现不可预期的资源释放问题 - 查询性能缺陷:
like '%xxx'左模糊查询无法走索引,数据量越大查询耗时越长,循环调用累计延迟会表现为连接冻结 - 类库兼容性问题:System.Data.SqlClient已停止功能更新,对.NET Core 5的兼容性不如微软官方推荐的
Microsoft.Data.SqlClient类库,存在已知的连接bug
优化后代码
// 连接字符串构建器静态复用,避免重复初始化 private static readonly SqlConnectionStringBuilder _connBuilder = new SqlConnectionStringBuilder { DataSource = "server01", UserID = "user1", Password = "SecretPassword", InitialCatalog = "archiv1", // 新增连接池配置,避免连接池耗尽导致的冻结 MaxPoolSize = 200, ConnectionTimeout = 15 }; public List<Contract> ReadDBView(Contract contract) { List<Contract> contracts = new List<Contract>(); // 前置参数校验,避免空引用异常 if (contract == null || string.IsNullOrWhiteSpace(contract.Number?.ToString())) { return contracts; } try { // 修正SQL语法错误,使用参数化查询 string sql = "SELECT name, group_name, group_country_code FROM [dbo].[GROUPS] where number like @NumberFilter"; using (SqlConnection connection = new SqlConnection(_connBuilder.ConnectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(sql, connection)) { // 添加参数,自动处理特殊字符转义 command.Parameters.AddWithValue("@NumberFilter", $"%{contract.Number}"); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { // 每次循环新建Contract实例,避免引用共用问题 var resultContract = new Contract { // 处理DBNull空值 DealerName = reader.IsDBNull("name") ? string.Empty : reader["name"].ToString(), GroupName = reader.IsDBNull("group_name") ? string.Empty : reader["group_name"].ToString(), Country = reader.IsDBNull("group_country_code") ? string.Empty : reader["group_country_code"].ToString(), Number = contract.Number // 其他需要赋值的属性按需求补充 }; contracts.Add(resultContract); } } } // 移除冗余的connection.Close()调用 } } catch (SqlException e) { Console.WriteLine(e.ToString()); // 可根据业务需求添加日志、重试逻辑 } return contracts; }
连接冻结问题解决方案
- 替换类库:将
System.Data.SQLClient 4.8.2替换为最新稳定版的Microsoft.Data.SqlClient,修复.NET Core下的已知连接bug - 优化查询:业务允许的前提下将左模糊查询改为右模糊
like 'xxx%',或给number字段添加全文索引,大幅提升查询速度 - 并发控制:如果是高频循环调用,建议添加本地缓存,相同
Number的查询结果缓存3~5秒,避免重复访问数据库 - 异常重试:新增SQL执行失败重试机制,避免网络抖动导致的连接假死
- 连接池调整:根据实际并发量调整连接字符串中的
Max Pool Size参数,默认值为100,高并发场景可适当调大,避免连接池耗尽导致的请求等待
内容的提问来源于stack exchange,提问作者user3732793
相关产品推荐
相关产品推荐

