MySQL×JDBC×JSP:文字コード

ボクの環境(Mac OSX)で,文字コードでかなり苦戦したので,メモがてら書いておきます.

どこで躓いたか?

今授業で,「データベースにアクセスして,図書を検索する」というのをやっています.それでやっているうちに,何度となく文字化けに悩まされ,何度となく解消してきました.
しかし前日,フォームの入力から図書を検索する,というところで,日本語を入力するとクエリが文字化けし,正確に検索できないという事がありました.というのも,データベースの方の文字コードがLatin-1(ISO-8859-1)に対し,クエリがUTF-8だったからです.
これで,図書一覧は(回りくどい方法でしたが)問題無く*1表示できたし,このままでイケルと思ってたんだけど,入力に日本語が絡んでくると,途端牙を剥いたんですね.

MySQL

create database

まずは,MySQLの方から問題を解決していきます.そもそも,なぜLatin-1なんだ?
試しに,「hoge」というデータベースを作ってみます.

mysql> create database hoge;
Query OK, 1 row affected (0.01 sec)

次に,データベースを「hoge」に設定して

show variables like 'character\_set\_%';

とすると,文字コードの一覧が見れます.

mysql> use hoge
Database changed
mysql> show variables like 'character\_set\_%';
+--------------------------+--------+
| 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   |
+--------------------------+--------+
7 rows in set (0.00 sec)

と,デフォルトのままでは文字コードの設定ががLatin-1と,相当よろしくない.インストールのときのオプションでミスったのかも.しかしながら,いちいちインストールし直すのも面倒くさいので,簡単なテクニックで解決です.
先ずは「hoge」をドロップしちまって,作り直しましょうか.

mysql> drop database hoge;
Query OK, 0 rows affected (0.00 sec)

次に,データベースを作成.この時,オプションを指定します.

mysql> create database hoge collate sjis_japanese_ci;
Query OK, 1 row affected (0.02 sec)

mysql> use hoge
Database changed
mysql> show variables like 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | latin1 |
| character_set_connection | latin1 |
| character_set_database   | sjis   |
| character_set_filesystem | binary |
| character_set_results    | latin1 |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+
7 rows in set (0.00 sec)

この程度ではまだ駄目ですね.mysql:9586によると,

character_set_client
クライアントから渡された SQL 文はこの文字コードであると解釈される。

character_set_connection
キャラクタセットイントロデューサ (例えば『_ujis'ほげ'』)が省略されたSQL 文中の文字列リテラルはこの文字コードであると解釈される。

character_set_results
サーバーがクライアントに返す結果をこの文字コードに変換する。この変数を NULL にセットすると、結果に対する文字コード変換をしないようにできる。

との事ですので,この辺りをShift-JISにしない事には,ちゃんとクエリの解釈をShift-JISで解釈してくれないでしょう.また,帰ってくるのもLatin-1なので,手間がかかります.
そこで,

set character set sjis;

とすると,これらの値をShift-JISに変換できます.やってみます.

mysql> set character set sjis;
Query OK, 0 rows affected (0.01 sec)

mysql> show variables like 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | sjis   |
| character_set_connection | sjis   |
| character_set_database   | sjis   |
| character_set_filesystem | binary |
| character_set_results    | sjis   |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+
7 rows in set (0.00 sec)

ちゃんとsjisになってます.なぜかcharacter_set_serverだけはlatin1のままですが,これはどーでも良い.
これでひとまず,データベースの設定はできました.

create table

次に,テーブルを作ります.コレはもう普通に,

mysql> CREATE TABLE books ( id INT, name VARCHAR(255), 
publisher VARCHAR(255), author VARCHAR(255), arrivedate DATE, 
isbn INT, PRIMARY KEY (id) );

てするだけ.特にテクニックは必要ありません.

要素をファイルから読み込む

テーブルの要素をファイルから読み込む場合,文字コードをShift-JISに,改行コードをLFにしておけば,まず問題ありません.

JSP

とりあえずShift-JISに

まず,ソースコード自体の文字コードはShift-JISにしましょう.
次に,JSPのソースです.

<%@ page pageEncoding="SJIS" contentType="text/html; charset=SJIS" %>

ヘッダと呼べば良いのでしょうか,はじめの行です.charsetをSJISにしています.
次にurlはどうすれば良いか?

String url = "jdbc:mysql://localhost/bookdb?characterEncoding=sjis";

characterEncodingをsjisにして繋いでいます.
クエリも同様にして,

request.setCharacterEncoding("Shift-JIS");

とします.これでクエリがShift-JISになります.

ResultSet

次に,MySQLから帰ってくるのはどうするのか.
まだLatin-1とかで頑張っていたときは,

new String(rs.getString("name").getBytes("ISO-8859-1"))

などと回りくどい事をしていましたが,オールShift-JISにしてしまうと

rs.getString("name")

で完了.なんて楽なんだっ!

とりあえず大丈夫?

一応,ボクの環境だとこんなかんじで問題無く出来ています.ボクのを参考にしてやったのにデキネーヨ!なんて事があったら,是非教えて欲しいです.「こんな方法もあるよ」とかあれば,是非コメントして欲しいです.
ではでは.

*1:一部,ソフトバンクがャtトバンクになったりしてたけど