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

ASP.NET MVC+EF6+MySQL下FirstOrDefault触发集合已修改异常求助

问题本质

这个异常的根本原因是Connector/NET 8.0.19版本中FailoverManager类的共享集合没有实现线程安全控制,多线程并发触发数据库连接打开操作时,会出现集合被修改同时被遍历的冲突。爬虫请求通常并发度更高,更容易触发该类线程安全问题。

可行解决方案(按落地优先级排序)


方案1:绕过内置多主机负载逻辑(推荐快速修复)

放弃Connector/NET内置的多主机负载均衡能力,改用HAProxy、LVS等第三方负载均衡组件代理数据库请求,应用层仅配置单个代理节点的连接字符串,完全绕过有问题的FailoverManager代码。修改后的连接字符串格式如下:

Server=负载均衡代理地址; Database=myDataBase; Uid=myUsername; Pwd=myPassword;

该方案无需修改业务代码,稳定性最高,适合快速上线解决问题。

方案2:加全局锁控制连接并发

如果暂时无法部署负载均衡组件,可以给MySQL连接的打开操作加全局锁,避免多线程同时触发连接字符串解析逻辑,实现步骤如下:

  1. 自定义EF连接拦截器
public class MysqlConnectionLockInterceptor : DbConnectionInterceptor
{
    private static readonly object _connLock = new object();
    
    public override void Opening(DbConnection connection, DbConnectionInterceptionContext interceptionContext)
    {
        Monitor.Enter(_connLock);
        base.Opening(connection, interceptionContext);
    }

    public override void Opened(DbConnection connection, DbConnectionInterceptionContext interceptionContext)
    {
        Monitor.Exit(_connLock);
        base.Opened(connection, interceptionContext);
    }

    public override void OpenFailed(DbConnection connection, DbConnectionErrorInterceptionContext interceptionContext)
    {
        if (Monitor.IsEntered(_connLock))
        {
            Monitor.Exit(_connLock);
        }
        base.OpenFailed(connection, interceptionContext);
    }
}
  1. 应用启动时注册拦截器
DbInterception.Add(new MysqlConnectionLockInterceptor());

该方案仅会轻微影响数据库连接建立的并发性能,对普通流量规模的站点完全可接受。

方案3:调整Connector/NET版本

当前使用的8.0.19版本仍存在未修复的FailoverManager线程安全bug,可以尝试升级到最新的8.0.x稳定版,或者降级到经过验证无该问题的历史版本,降级前需做好EF6兼容性测试。

方案4:自定义修复驱动代码

如果对Connector/NET源码熟悉,可以将FailoverManager相关代码拷贝到本地项目,给涉及共享集合读写的位置补充读写锁,编译后替换官方的MySQL.Data.dll即可。


内容的提问来源于stack exchange,提问作者Hooman Bahreini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 06:39:01