読者です 読者をやめる 読者になる 読者になる

よかろうもん!

アプリからインフラまで幅広くこなすいまどきのクラウドエンジニアが記す技術ブログ

MySQLでcharacter_set_databaseがlatin1になってしまう問題の対応方法

アプリケーションのバージョンアップなどでテーブル追加を伴うスキーマ変更があった場合に、テーブル追加したところのデータだけ画面で「????」になって表示されてしまうことが稀にあります。
この対応方法について、発生理由と共に簡単に解説しておこうと思います。


結果だけを先に書いておくと、今回の根本原因はAmazonRDSを起動するときのパラメータグループの初期設定が不十分で、初回create database時に default character set に想定外のものがセットされていたためです。
下記ではその原因を特定する方法と解決方法を示していきます。


まずは文字化けした時に状況確認を行ってみてください。おそらくは下記のような状況になっているかと思います。※今回は文字コードを全てutf8に統一しているものとします。

まずは文字化けしているテーブルの情報を確認してみます。

mysql> show create table notifications;

Table Create Table

| notifications | CREATE TABLE `notifications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`title` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`link` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `index_notifications_on_user_id` (`user_id`),
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 |

CHARSETが latin1 になっていますね。本来は utf8 になるべきなのに。

では、なぜ latin1 になっているのかを確認します。


MySQLでは、サーバ全体/データベース/テーブル/カラム という括りで文字コードを指定できるようになっています。
データベース作成時に文字コードが指定されていなかったら、サーバ全体で設定されている情報を参照して作成されます。
同様にテーブル作成時も、文字コード指定がなかったらデータベースで指定されている文字コードを適用します。カラムについても同様のロジックです。


なので、テーブル作成時に参照されたデータベースの文字コード情報を確認したら latin1 になっているはずですので、それを確認してみます。


mysql> show variables like 'character%';

Variable_name Value
character_set_client utf8
character_set_connection utf8
character_set_database latin1
character_set_filesystem binary
character_set_results utf8
character_set_server utf8
character_set_system utf8


character_set_database だけが latin1 になっています。
念のためにSESSIONの情報ではなくGLOBALの情報も確認しておきます。


mysql> show global variables like 'character%';

Variable_name Value
character_set_client utf8
character_set_connection utf8
character_set_database utf8
character_set_filesystem binary
character_set_results utf8
character_set_server utf8
character_set_system utf8

こちらはパラメータグループで設定されている値が反映されていますね。


mysqlのコネクションを何度も繋ぎ直してもshow variablesの出力値は変化しないため、テーブル作成時はここでセットされている値(latin1)が参照されます。
では、この値はどこを参照しているかというと、create database した時の値です。

確認コマンドは以下です。


mysql> show create database `railsapp_staging`;

Database Create Database
railsapp_staging CREATE DATABASE `railsapp_staging` /*!40100 DEFAULT CHARACTER SET latin1 */


確かにdefalut character set が latin1 になっていますね。


これで原因は特定できました。
あとは解消するためにはどうすれば良いか、です。

まずは、新規にテーブルが作成された時に latin1 で作成されないようにする必要があります。

変更のコマンドは、こちらです。


mysql> ALTER DATABASE `railsapp_staging` default character set utf8;

※ALTER DATABASEの仕様
MySQL :: MySQL 5.6 Reference Manual :: 13.1.1 ALTER DATABASE Syntax
MySQL :: MySQL 5.1 リファレンスマニュアル :: 12.1.1 ALTER DATABASE 構文


これで、データベースの文字コードが utf8 になるはずです。
以下のコマンドで確認できます。


mysql> show create database `railsapp_staging`;

Database Create Database
railsapp_staging CREATE DATABASE `railsapp_staging` /*!40100 DEFAULT CHARACTER SET utf8 */


サーバ設定も更新されていますね。


mysql> show variables like 'character%';

Variable_name Value
character_set_client utf8
character_set_connection utf8
character_set_database utf8
character_set_filesystem binary
character_set_results utf8
character_set_server utf8
character_set_system utf8

他にも、テーブル/カラムの文字コードも変更してあげないと文字化けは解消しません。
これについては、http://kzworks.at.webry.info/200903/article_14.html で解説してあるようなので、参考にしてみてください。


今回は latin1 で生成されたテーブルをDrop/Createして再生成することで、文字コードが utf8 になり、文字化けが発生しなくなることは確認できました。

困ったときは上記手順でお試しあれ。



あわせて読みたい