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

多线程环境下MySQL.NET连接报错致IIS应用池挂起问题咨询

MySQL 8.0.35 + Connector 8.3.0 多线程环境连接失败及应用池挂起问题排查与修复

问题描述

长期使用MySQL.NET Connector 5.x,升级项目至MySQL 8.0.35及Connector 8.3.0后,单线程运行正常,但多线程环境下线程数达到12个时,出现Unable to Connect to Any of the Specified MySQL Hosts错误,随后IIS应用池直接挂起。原有代码流程为:

Open the connection
Process
Close the connection
该流程在多线程环境中被循环调用,旧版本连接器下无任何问题。

相关代码如下:

Public Shared Function pustest(ByVal busid As Integer) As String
    Dim d As New pustest_Delegate(AddressOf pustest1)
    Dim R As IAsyncResult = Nothing
    R = d.BeginInvoke(busid, Nothing, Nothing)
End Function

Private Delegate Sub pustest_Delegate(ByVal busid As Integer)
Private Shared Function pustest1(ByVal busid As Integer) As String
    Dim con As MySqlConnection
    Dim str As String = "insert into tblins(bid, dte) values('" & busid & "','" & dbnow(0).DB_yyyyMMdd_HHmmss & "')"
    con = dcon1(myConfig.DB)
    dbcommand(str, con)
    Dim sd As String = busid
    con.Close()
End Function

调用代码:

Dim ik As Integer = 1
While ik < 15000
    pustest(ik)
  
    Response.Write("<br>" & dbnow(0).DS_ddMMMyyyy_hhmm_tt & " - " & ik & " - " & sval & "<br>")
    ik = ik + 1
End While

代码问题分析

  1. 异步委托资源泄漏:pustest里用BeginInvoke启动异步任务,但从未调用EndInvoke回收线程资源。循环15000次会堆积大量未回收的线程,直接耗尽IIS应用池的线程配额,引发连接失败和池挂起。
  2. 连接未可靠释放:虽然写了con.Close(),但如果dbcommand执行时抛出异常,Close()根本不会执行,连接无法归还到连接池。Connector 8.x对连接池的管理比5.x严格得多,未释放的连接会快速耗尽池资源。
  3. SQL硬编码风险:直接拼接参数到SQL语句里,不仅有SQL注入漏洞,还可能因数据格式问题触发异常,进一步加剧连接泄漏。
  4. 连接池配置不匹配:Connector 8.x默认的连接池参数(比如max pool size)和5.x不同,当并发线程数超过池上限时,会导致连接等待超时,最终触发连接失败。

解决方案

1. 修复异步委托,回收线程资源

要么用EndInvoke回收旧的异步资源,要么换成更现代的Async/Await模式:

' 推荐使用Async/Await
Public Shared Async Function pustest(ByVal busid As Integer) As Task(Of String)
    Await Task.Run(Function() pustest1(busid))
End Function

' 调用部分也要改为异步
Dim ik As Integer = 1
While ik < 15000
    Await pustest(ik)
    Response.Write($"<br>{dbnow(0).DS_ddMMMyyyy_hhmm_tt} - {ik} - {sval}<br>")
    ik = ik + 1
End While

如果必须用BeginInvoke,一定要加EndInvoke:

Public Shared Function pustest(ByVal busid As Integer) As String
    Dim d As New pustest_Delegate(AddressOf pustest1)
    Dim R As IAsyncResult = d.BeginInvoke(busid, Nothing, Nothing)
    ' 等待异步完成并回收资源
    d.EndInvoke(R)
End Function

2. 用Using语句确保连接自动释放

不管是否发生异常,Using都会自动关闭并归还连接到池:

Private Shared Function pustest1(ByVal busid As Integer) As String
    Dim str As String = "insert into tblins(bid, dte) values(@busid, @dte)"
    ' Using包裹连接,自动释放
    Using con As MySqlConnection = dcon1(myConfig.DB)
        Using cmd As New MySqlCommand(str, con)
            ' 参数化查询,避免注入
            cmd.Parameters.AddWithValue("@busid", busid)
            cmd.Parameters.AddWithValue("@dte", dbnow(0).DB_yyyyMMdd_HHmmss)
            con.Open()
            cmd.ExecuteNonQuery()
        End Using
    End Using
    Return busid.ToString()
End Function

3. 调整连接池配置

在连接字符串里明确配置池参数,适配高并发场景:

Server=你的服务器地址;Database=你的数据库;Uid=用户名;Pwd=密码;Max Pool Size=100;Min Pool Size=5;Connection Timeout=30;

根据实际并发量调整Max Pool Size,确保大于最大并发线程数。

4. 检查MySQL服务器配置

确保MySQL的max_connections足够大,允许连接池建立足够连接:

SHOW VARIABLES LIKE 'max_connections';

如果值过小,修改my.cnf(或my.ini)中的max_connections参数后重启MySQL服务。

总结

Connector 8.x对资源管理的要求比5.x严格很多,旧代码里的异步资源泄漏、连接未可靠释放等问题,在高并发下会被直接放大。通过修复异步调用、确保连接自动释放、改用参数化查询、调整连接池配置,就能解决多线程环境下的连接失败和应用池挂起问题。

内容的提问来源于stack exchange,提问作者Maheshwaran Deveraj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:23:21