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 になり、文字化けが発生しなくなることは確認できました。
困ったときは上記手順でお試しあれ。
■ あわせて読みたい