You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF应用出现Sql连接池超时异常,寻求解决方案

解决数据库连接池超时问题的方案

根本原因

你的代码存在无限递归调用,短时间内创建大量数据库连接导致连接池耗尽:

  • 当UserName属性的setter触发时,会调用UsersCollection.GetAllUserNames()拉取所有用户名
  • GetAllUserNames()中每读取一个用户名,就会通过Users.GetUserNamesFromResultSet(reader)创建Users对象
  • 若Users构造函数是通过UserName属性赋值(而非直接操作私有字段),会再次触发UserName的setter,进而重复调用GetAllUserNames(),形成无限递归
  • 每次递归都会打开新的数据库连接,连接池被快速占满,最终抛出超时异常

具体修复步骤

1. 修复Users构造函数,终止递归

确保构造函数直接给私有字段_username赋值,不触发属性setter:

// 在Users类中添加对应构造函数
public Users(string username)
{
    // 直接操作私有字段,避免触发UserName属性的setter
    _username = username;
}

2. 优化用户名重复检查逻辑,减少连接消耗

不要一次性拉取所有用户名到内存遍历,改成直接在数据库中查询目标用户名是否存在,仅需一次数据库交互:

// 替换UserName setter中检查重复的代码段
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString))
{
    conn.Open();
    string checkSql = "SELECT COUNT(1) FROM Users WHERE UserName = @UserName";
    using (SqlCommand command = new SqlCommand(checkSql, conn))
    {
        command.Parameters.AddWithValue("@UserName", value);
        int count = (int)command.ExecuteScalar();
        if (count > 0)
        {
            errors.Add("Username already exist.");
            SetErrors("UserName", errors);
            valid = false;
        }
    }
}

3. 避免在属性setter中执行耗时操作(推荐优化)

属性setter应仅负责快速赋值和通知变更,将验证逻辑移到专门方法中,在需要时(如用户提交表单)调用:

// 在Users类中添加专用验证方法
public bool ValidateUserName(string userName)
{
    List<string> errors = new List<string>();
    bool valid = true;

    if (string.IsNullOrEmpty(userName) || userName.Length < 5)
    {
        errors.Add("Username can not have less than 5 characters.");
        SetErrors("UserName", errors);
        valid = false;
    }

    // 数据库重复检查
    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString))
    {
        conn.Open();
        string checkSql = "SELECT COUNT(1) FROM Users WHERE UserName = @UserName";
        using (SqlCommand command = new SqlCommand(checkSql, conn))
        {
            command.Parameters.AddWithValue("@UserName", userName);
            int count = (int)command.ExecuteScalar();
            if (count > 0)
            {
                errors.Add("Username already exist.");
                SetErrors("UserName", errors);
                valid = false;
            }
        }
    }

    if (!Regex.Match(userName, @"^\w+$").Success)
    {
        errors.Add("Username can only contain letters, numbers and underscore characters.");
        SetErrors("UserName", errors);
        valid = false;
    }

    if (valid)
    {
        ClearErrors("UserName");
    }

    return valid;
}

// 修改UserName属性的setter,仅保留核心逻辑
public string UserName
{
    get { return _username; }
    set
    {
        if (_username == value) return;
        _username = value;
        OnPropertyChanged(new PropertyChangedEventArgs("UserName"));
    }
}

额外建议

  • 始终用using语句包裹数据库连接,确保连接被正确释放回连接池
  • 不要随意调整连接字符串的Max Pool Size参数,解决递归和逻辑问题才是根本

内容的提问来源于stack exchange,提问作者Aleksandar Veljkovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:17