推荐使用 mysql2 而非 mysql,因其支持 MySQL 5.7+ 认证协议、UTF8MB4 编码、连接重试及参数化查询,且持续维护;mysql 已于 2013 年停止更新,不兼容新认证与编码。

现在 Ruby 连接 MySQL 的主流、推荐、维护活跃的类库是 mysql2,不是过时的 mysql(已多年未更新)或历史更久的 dbi + dbd-mysql 组合。
为什么必须用 mysql2 而不是 mysql
mysql gem 依赖旧版 C API,不支持 MySQL 5.7+ 的认证协议(如 caching_sha2_password),在 macOS 13+/Ubuntu 22.04+ 或新版 MySQL Server 上直接报错:Access denied for user 或 Client does not support authentication protocol。而 mysql2 持续更新,原生支持现代认证、SSL、prepared statement、异步查询等特性,且是 Rails 默认适配器。
-
mysql2是纯 C 扩展,性能比纯 Ruby 实现高数倍 - Rails 6+、Hanami、Sinatra 生态默认绑定
mysql2,社区文档和错误排查资源丰富 -
mysqlgem 最后发布是 2013 年(v2.9.1),早已停止维护
mysql2 安装常见失败原因与解法
安装 gem install mysql2 报错,90% 是因为找不到 MySQL 客户端开发库(libmysqlclient)或路径不对,不是 Ruby 本身问题。
- Ubuntu/Debian:缺
libmysqlclient-dev→ 运行sudo apt-get install libmysqlclient-dev - CentOS/RHEL:缺
mysql-devel→ 运行sudo yum install mysql-devel(或dnf install mysql-devel) - macOS(Homebrew):MySQL 已安装但
mysql_config不在 PATH → 先确认which mysql_config,若为空则运行brew install mysql-client,再用gem install mysql2 -- --with-mysql-config=$(brew --prefix mysql-client)/bin/mysql_config - Windows:默认会下载预编译二进制,但若本地装了 MySQL Connector/C,可用
gem install mysql2 -- --with-mysql-dir="C:/mysql-connector-c-6.1"
Mysql2::Client.new 必填参数与安全陷阱
最简连接能跑通,不代表生产可用。漏掉关键选项会导致乱码、超时中断、连接泄漏或认证失败。
require 'mysql2'client = Mysql2::Client.new( host: '127.0.0.1', username: 'root', password: 'your_pass', database: 'myapp_development', encoding: 'utf8mb4', # ← 必须设!否则存 emoji 或中文可能变 ?? reconnect: true, # ← 建议开启,避免连接空闲断开后 query 报 "MySQL server has gone away" read_timeout: 10, write_timeout: 10, connect_timeout: 5 )
-
encoding: 'utf8mb4'是 MySQL 5.5.3+ 正确支持完整 Unicode 的编码,utf8在 MySQL 里其实是阉割版(最多 3 字节) - 不设
reconnect: true,长连接空闲超时(MySQL 默认wait_timeout=28800秒)后首次 query 会抛Mysql2::Error: MySQL server has gone away - 不要把密码硬编码在代码里,应通过环境变量(如
ENV['MYSQL_PASSWORD'])或配置文件注入
查、插、改、删基础操作与防 SQL 注入
mysql2 支持两种执行方式:字符串拼接(危险)和参数化查询(安全)。永远优先用后者。
# ✅ 安全:参数化查询(自动转义)
result = client.query("SELECT * FROM users WHERE name = ? AND age > ?", "Alice", 18)
❌ 危险:字符串插值(易被注入)
name = "Alice'; DROP TABLE users; --"
client.query("SELECT * FROM users WHERE name = '#{name}'") # ← 直接崩库
插入示例(返回影响行数)
client.query("INSERT INTO posts (title, body) VALUES (?, ?)", "Hello", "World")
批量插入(效率更高)
client.query("INSERT INTO logs (msg, level) VALUES (?, ?), (?, ?)", "start", "info", "end", "warn")
-
query方法只用于 SELECT;INSERT/UPDATE/DELETE 推荐也用query(它统一返回Mysql2::Result或影响行数),无需区分 - 想获取自增 ID?用
client.last_id(刚执行 INSERT 后立即读) - 事务用
client.query('START TRANSACTION')+client.query('COMMIT'),但更建议用 ActiveRecord 或自己封装 begin/rescue/rollback
真正容易出问题的不是“连不上”,而是连上了却因编码、超时、认证方式、SQL 拼接等细节导致数据错乱或服务偶发崩溃。这些点没有报错提示,但上线后会静默毁数据。










