推荐使用 MySqlConnector 替代 MySql.Data,因其原生支持 async/await、无全局锁、兼容 .NET 6+;连接字符串兼容无需修改;须用 await using 管理连接生命周期;参数绑定必须用 @ 符号并避免 AddWithValue;需用户变量时添加 Allow User Variables=true。

安装 MySqlConnector 而不是 MySql.Data
官方 MySql.Data 包在 .NET 6+ 上存在隐式线程同步、连接池不稳定、异步方法实际是同步伪装等问题,尤其在高并发 Web 场景下容易卡死或抛 MySqlException: Timeout expired。推荐直接用开源替代品 MySqlConnector,它原生支持 async/await、无全局锁、兼容 .NET Core / .NET 5+。
实操建议:
- 通过 NuGet 安装:
dotnet add package MySqlConnector - 代码中 using 语句写
using MySqlConnector;,不是MySql.Data.MySqlClient - 连接字符串格式完全兼容,无需修改(如
"Server=localhost;Database=test;Uid=root;Pwd=123;")
正确写法:用 MySqlConnection + await using 管理生命周期
常见错误是手动调用 Open() 后忘记 Close(),或在异常路径下连接泄漏;更隐蔽的问题是复用同一个 MySqlConnection 实例跨线程或跨 await —— 这会触发 InvalidOperationException: Connection is already in use。
实操建议:
- 永远用
await using var conn = new MySqlConnection(connStr);,让 Dispose 自动释放连接 - 每个查询/命令都新建连接,别缓存
MySqlConnection对象 - 执行命令时必须用
await cmd.ExecuteReaderAsync()或await cmd.ExecuteNonQueryAsync(),别混用同步方法
await using var conn = new MySqlConnection(connStr);
await conn.OpenAsync();
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT id, name FROM users WHERE id = @id";
cmd.Parameters.Add(new MySqlParameter("@id", userId));
await using var reader = await cmd.ExecuteReaderAsync();参数绑定必须用 @ 符号,别拼 SQL
手拼字符串如 "SELECT * FROM users WHERE name = '" + name + "'" 会直接导致 SQL 注入,且 MySQL 对单引号、反斜杠等字符处理严格,容易报 MySqlException: You have an error in your SQL syntax。
实操建议:
- 所有用户输入必须走
cmd.Parameters.Add(new MySqlParameter("@name", name)) - MySQL 参数名以
@开头(不是:或$),且命名需与 SQL 中一致 - 不要用
AddWithValue—— 它可能推断错类型(比如把空字符串当TEXT而非VARCHAR),引发隐式转换失败
连接字符串里别漏 Allow User Variables=true
如果后续要执行带用户变量的 SQL(如 SET @row := 0; SELECT @row := @row + 1 AS row_num, name FROM users),默认连接会拒绝执行,抛 MySqlException: User variable '@row' is not allowed。
实操建议:
- 在连接字符串末尾加上
;Allow User Variables=true - 仅当真需要变量时才加,否则不加 —— 这是额外解析开销,且部分托管环境(如 Azure Database for MySQL)禁用该选项
- 注意等号前后不能有空格,必须是
Allow User Variables=true,不是allow_user_variables=true
连接池默认开启,但超时和最大连接数得自己盯 —— Connection Timeout=30 和 Maximum Pool Size=100 这类配置不写就用默认值,线上出问题时往往卡在这儿。


















