C#调用MySQL存储过程报SocketException连接超时问题排查
问题根因
- 你碰到的10060错误本质是命令执行超时,不是数据库连接失败。MySql.Data驱动默认的命令执行超时是30秒,你的存储过程实际执行时间超过这个阈值后,驱动会主动断开TCP连接,最终抛出Socket响应超时的错误。你直接在数据库客户端执行存储过程能成功,是因为多数数据库GUI客户端默认不会设置这么短的执行超时限制。
- 存储过程存在严重的逻辑冗余:你写的WHILE循环会按照cpe表的总行数重复执行N次,但循环体内的INSERT语句是完全相同的全表分组查询逻辑,没有用到循环变量i做任何分批过滤,等于把同一个全表扫描+分组+插入的操作重复跑N遍。只要cpe表数据量超过几千行,执行时间会线性暴涨,必然触发超时。
- C#代码存在隐性问题:你声明了值为null的MySqlTransaction对象,还把这个null赋值给了cmd.Transaction属性,虽然当前场景没触发异常,但后续开启事务时极易引发空引用错误。
修复方案
1. 先优化存储过程,删除无意义的循环
你的需求本质是把cpe表按cveMatch分组统计后插入cve表,单条INSERT...SELECT语句就能完成,完全不需要套循环,优化后存储过程执行效率会提升N个数量级:
DROP PROCEDURE IF EXISTS cveTableFill; DELIMITER ;; CREATE PROCEDURE cveTableFill() BEGIN INSERT IGNORE INTO cve(cve_name, cpeMatchCount) SELECT c.cveMatch, COUNT(c.cveMatch) FROM cpe c GROUP BY c.cveMatch HAVING COUNT(c.cveMatch) > 0; END;; DELIMITER ;
如果确实因为数据量过大需要分批插入,也要在循环内加主键/时间范围过滤条件,每次只处理一批数据,不要每次循环都扫描全表。
2. 修复C#代码问题,调整超时配置
- 删除无效的null事务赋值,需要用事务时显式从连接对象创建,执行完成后提交
- 给SqlCommand设置合理的超时时间,适配长耗时操作场景
- 异常打印时输出完整堆栈,不要只打Message字段,方便定位问题
修复后的代码如下:
业务方法代码
public void BasicCveInfoFill() { try { using(MySqlConnection conn = GetConnection()) { conn.Open(); // 不需要事务可以删掉下面这行using块 using(MySqlTransaction transaction = conn.BeginTransaction()) { using(MySqlCommand cmd = new MySqlCommand()) { cmd.Connection = conn; cmd.Transaction = transaction; cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "cveTableFill"; // 命令超时时间单位为秒,根据实际数据量调整,这里示例设为5分钟 cmd.CommandTimeout = 300; var affectedRows = cmd.ExecuteNonQuery(); // 开启事务必须调用Commit,否则操作会回滚 transaction.Commit(); } } } } catch(Exception ex) { // 打印完整异常信息,不要只打ex.Message Console.WriteLine(ex.ToString()); } }
数据库连接方法代码
public MySqlConnection GetConnection() { // 也可以在连接字符串中配置全局默认命令超时,单位同样是秒 string connString = @"server=localhost;user=root;database=test;password=;Default Command Timeout=300"; return new MySqlConnection(connString); }
3. 存储过程执行状态判断方法
- 正常情况下
ExecuteNonQuery()方法会阻塞等待存储过程执行完成,方法正常返回、拿到受影响行数就代表存储过程执行成功;方法抛出异常即代表执行过程中出现错误,不需要额外做状态轮询。 - 如果需要排查长耗时存储过程的执行进度,可以在MySQL中执行
show processlist命令,查看对应会话的执行状态、已运行时间、当前执行的SQL片段,判断任务是否正常运行。 - 不建议将命令超时设置为无限大,如果优化SQL后单次操作仍需要超过10分钟执行时间,优先考虑改成分批处理逻辑,避免长时间占用数据库连接引发其他问题。
内容的提问来源于stack exchange,提问作者DuckDuckGoose
相关产品推荐
相关产品推荐

