MySQL を使った Web システムの移行作業をした。
何年か前に作成したもので、DB とのやり取りをする部分は Perl による CGI 形式になっている。
枯れた技術最高!(笑)
あ、今回は Perl ではなく MySQL の話ね(^^;
移行先にも MySQL は入っていたので、早速、移行元で、
# mysqldump -u root -p --default-character-set=binary hoge_db > hoge_db.sql
と、バイナリデータとしてバックアップ。
このデータを移行先サーバに持ち込み、
# mysql -u root --default-character-set=binary hoge_db < hoge_db.sql
と、DB にリストアした。(もちろん、予め空の DB を作っておく)
早速 mysql コマンドで SELECT をしてみると、文字化け~。表示できなかった文字が ? に置換されとる。
DB を確認すると、
mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
なんか、文字コードが「ラテン語」になっとるやないか。
/etc/my.cnf の mysqld、client セクションに、それぞれ、
[mysqld]
character-set-server = utf8
[client]
default-character-set = utf8
を追加し、DB 確認。
mysql> show variables like '%char%';
+--------------------------+----------------------------+
| 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 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
お~。この時点で、mysql コマンド上での文字化けはなくなった。
しかし、CGI からのアクセスでは相変わらず文字が化ける。
こういう場合は、だいたい DBI/DBD モジュールの問題だ。
案の定、このサーバ上で make された DBD::MySQL は mysql_enable_utf8 を設定されていないようで、そのため「DBに格納されている通常の utf8 文字列は、エンコード失敗の ? に置換されDBから取り出される。」ようだ。
その証拠に、mysql_enable_utf8 を設定した場合と同じ効果のある「SET NAMES utf8」という SQL 文を、本来の SQL 文を処理する前に DB に送るようにしたら文字化けは解消した。(db_tool::directExec というのは当社独自の DB アクセス関係の関数)
# 先に SET NAMES utf8 を発行
my $set_sql =<<EOS;
SET NAMES utf8
EOS
@db = &db_tool::directExec($Conn, $set_sql);
# 次に SELECT を実行
$sql =<<EOS;
SELECT
COUNT(id) AS count
FROM
hoge_data_list
WHERE
ID = $USER_ID
EOS
@db = &db_tools::directExec($Conn, $sql);
<以下略>
こんな感じで。
これで CGI でも文字化けは解消された。
ちなみに、db_tools::directExec 関数の中で「SET NAMES utf8」を発行するようにすれば、CGI 側で修正する必要はなくなるんだけど、この関数、他の人も使ってるからなあ・・・あんまり触りたくない。