现在 Ruby 连接 MySQL 的主流、推荐、维护活跃的类库是
mysql2,不是过时的
mysql(已多年未更新)或历史更久的
dbi + dbd-mysql组合。
为什么必须用 mysql2
而不是 mysql
mysqlgem 依赖旧版 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-devCentOS/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_configWindows:默认会下载预编译二进制,但若本地装了 MySQL Connector/C,可用
gem install mysql2 -- --with-mysql-dir="C:/mysql-connector-c-6.1"
Mysql2::Client.new
必填参数与安全陷阱
最简连接能跑通,不代表生产可用。漏掉关键选项会导致乱码、超时中断、连接泄漏或认证失败。
require 'mysql2' <p>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 )</p>
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)
<h1>❌ 危险:字符串插值(易被注入)</h1><p>name = "Alice'; DROP TABLE users; --"
client.query("SELECT * FROM users WHERE name = '#{name}'") # ← 直接崩库</p><h1>插入示例(返回影响行数)</h1><p>client.query("INSERT INTO posts (title, body) VALUES (?, ?)", "Hello", "World")</p><h1>批量插入(效率更高)</h1><p>client.query("INSERT INTO logs (msg, level) VALUES (?, ?), (?, ?)", "start", "info", "end", "warn")</p>
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 拼接等细节导致数据错乱或服务偶发崩溃。这些点没有报错提示,但上线后会静默毁数据。
