多线程环境下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
代码问题分析
- 异步委托资源泄漏:
pustest里用BeginInvoke启动异步任务,但从未调用EndInvoke回收线程资源。循环15000次会堆积大量未回收的线程,直接耗尽IIS应用池的线程配额,引发连接失败和池挂起。 - 连接未可靠释放:虽然写了
con.Close(),但如果dbcommand执行时抛出异常,Close()根本不会执行,连接无法归还到连接池。Connector 8.x对连接池的管理比5.x严格得多,未释放的连接会快速耗尽池资源。 - SQL硬编码风险:直接拼接参数到SQL语句里,不仅有SQL注入漏洞,还可能因数据格式问题触发异常,进一步加剧连接泄漏。
- 连接池配置不匹配: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
相关产品推荐
相关产品推荐

