当前位置: 首页 > 工具软件 > rails_emoji > 使用案例 >

阿里云 mysql utf8mb4_阿里云 Rails 项目调整 RDS MySQL 编码为 utf8mb4 的详细步骤

丁灿
2023-12-01

最近,将一个部署在阿里云上的 Rails 项目,连接的 MySQL 数据库的编码,由 utf8 调整为 utf8mb4。

实施过程不是非常顺利,目前,已经部署完成,观察了一段时间,比较稳定。

写了本篇总结,希望可以帮到有需要的朋友。

环境说明

服务器系统 Centos,版本为 6.5;

数据库使用的是阿里云 RDS MySQL,版本为 5.5.18;

Rails 版本为 4.1.2;

mysql2 Gem, 版本为 0.3.16。

为什么要使用 utf8mb4 编码

根本的原因在于,采用 utf8 编码的 MySQL 无法保存占位是 4 个字节的 Emoji 表情。

为了使后端的项目,全面支持客户端输入的 Emoji 表情,升级编码为 utf8mb4 是最佳解决方案。

之前一篇博文有讲到,不调整 MySQL 编码,使用 rumoji 替换 Emoji 表情为字母编号。

博客原文链接:Ruby on Rails Use MySQL DB Support iPhone emoji

http://manageyp.github.com/ruby-on-rails/2014/12/10/ruby-on-rails-use-mysql-db-support-iphone-emoji.html

但是,这样处理至少有两个问题:

Emoji 表情会持续的更新,rumoji 库如果没有及时更新,输入新的表情,则会报错。

使用 rumoji 对用户输入的字符,做正则匹配解析,增加了系统的开销,降低了性能。

另外,看到很多网友建议,迁移 MySQL 至 PostgreSQL、MongoDB 等,迁移成本不小,暂时不考虑。

备注:MySQL 5.5.3 版本之后,引入了 utf8mb4 字符集。

在 mysql client 端,输入以下命令,确认 mysql server 是否支持 utf8mb4 编码。

mysql> SHOW CHAR SET WHERE Charset LIKE "%utf8%";

+---------+---------------+--------------------+--------+

| Charset | Description | Default collation | Maxlen |

+---------+---------------+--------------------+--------+

| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |

| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |

+---------+---------------+--------------------+--------+

至于排序规则(collation)选择默认的 utf8mb4_general_ci,还是 utf8mb4_unicode_ci。

请参考下面文章的介绍,Character Set & Collation In MySQL:

http://infopotato.com/blog/index/mysql_character_set_and_collation

作者从排序的准确性,以及性能方面,告诉我们应该选用 utf8mb4_unicode_ci 。

实施的步骤

(1)在阿里云 RDS 控制台,新建一个数据库

名称为:production_new

字符集选择:utf8mb4

(2)修改 database.yml 编码

# config/database.yml

encoding: utf8mb4

(3)Ruby 程序接收和返回 JSON 数据时,强制使用 UTF-8 编码

"string".force_encoding("UTF-8")

(4)停止 Ruby 进程,停止队列等服务

(5)部署项目报错

正式版部署之前,有在本地和 Staging 做过测试。

信心满满的在正式版部署,执行的过程中,遇到下面的错误:

Character set 'utf8mb4' is not a compiled character setand is not specified inthe '/path/mysql/charsets/Index.xml' file

rake aborted!

Mysql2::Error: Can't initialize character set utf8mb4 (path: /path/mysql/charsets/)

/path/.rvm/gems/ruby-2.0.0-p598/gems/mysql2-0.3.16/lib/mysql2/client.rb:70:in `connect'

/path/.rvm/gems/ruby-2.0.0-p598/gems/mysql2-0.3.16/lib/mysql2/client.rb:70:in `initialize'

经过一番检查后发现,错误是由于当前系统上的 MySQL 客户端版本过低导致。

# 列出所有被安装的 mysql 包

rpm -qa | grepmysql

mysql-devel-5.1.73-3.el6_5.x86_64

mysql-5.1.73-3.el6_5.x86_64

mysql-libs-5.1.73-3.el6_5.x86_64

(6)移除现有的旧版本,重新安装 5.5 版本的客户端

# 清理现有 mysql

yum list installed | grep -i mysql

yum remove mysql mysql-*

# 修改安装源,不修改源,重新安装的仍然是 5.1 的版本

rpm -Uvh http://repo.webtatic.com/yum/el6/latest.rpm

# 安装 5.5 版本的 mysql client

yum installlibmysqlclient16 --enablerepo=webtatic

yum installmysql55w mysql55w-libs mysql55w-devel --enablerepo=webtatic

# 如果你需要安装 mysql server,请执行

yum installmysql55w-server --enablerepo=webtatic

(7)重新安装 mysql2 Gem

MySQL 5.5 客户端安装完毕之后,再次运行项目,同样出现上面的报错信息。

于是,决定重新安装一遍 mysql2 Gem。安装完成之后,项目运行正常。

# 重新安装 mysql2 Gem

gem uninstall mysql2

gem installmysql2 -v '0.3.16'

(8)备份和还原数据库

# 备份现有数据库

mysqldump -h host -u user -p production_old > production_old.sql

# 还原至新数据库

mysql -h host -u user -p production_new < production_old.sql

(9)执行调整单个表 (table) 编码的 SQL 文件

mysql -h host -u user -p production_new < db/sql/utf8mb4_charset.sql

SQL 文件内容,举例说明如下:

通常只需要修改 table 的编码,若该 table 内有字段 (column) 是 VARCHAR,或者 TEXT,

MySQL 将自动调整该字段的编码,与 table 的默认编码保持一致

ALTER TABLE `versions` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

MySQL 索引长度的限制错误

在执行 SQL 文件时,发现有些 table 更改编码时报错,信息如下:

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

报错原因在于:MySQL Innodb 的索引长度限制为 767 字节,UTF8mb4 字符集是 4 个字节,

767 字节 / 4 字节每字符 = 191 字符(即默认的索引最大长度)

因此在 varchar(255) 类型字段上,创建索引会失败,提示最大索引长度为 767 字节。

实践中发现,MySQL 5.5.x 的版本,只有 Unique 的索引,或者联合索引,才会报错。

普通索引,Rails 的 Migration 会自动对索引 Index 的长度增加一个 191 的限制。

而 MySQL 5.6.x 的版本,即使普通索引也会报错。

处理思路: 先移除索引,然后修改表的编码,修改成功之后。调整索引对应字段的长度为 191,最后再次创建索引。

ALTER TABLE `users` DROP INDEX index_users_on_email;

ALTER TABLE `users` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ALTER TABLE `users` MODIFY `email` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ALTER TABLE `users` ADD UNIQUE index_users_on_email (email);

# 查看一下最新的表结构

SHOW CREATE TABLE `users`;

(10)再次启动服务

使用 Migration 迁移 Table 编码

如果没有索引的问题,可以使用下面的代码,修改表的编码,简洁许多。

也可以使用下面的代码,打印 SQL 语句到 .sql 文件。

然后,对引起索引 Index 错误的 Table 单独增加处理的 SQL 语句。

def up

char_set = 'utf8mb4'

collation = 'utf8mb4_unicode_ci'

table_names = ActiveRecord::Base.connection.tables

table_names.each do |table_name|

execute "ALTER TABLE `#{table_name}` CONVERT TO CHARACTER SET#{char_set}COLLATE#{collation};"

end

end

 类似资料: