0
文字化け(MySQL→JDBC→DAO→サーブレット→JSP)
WindowsXP環境下のMySQLに作ってあるテーブルに "漢" というデータがあるのですが、これをJDBC経由で同じマシンのJSPに表示させようとしたところ、文字化けして困っています。どうやらDAOの時点ですでに文字化けしているようなんです。
MySQLの設定は、次のようになっていました。
Connection id: 7
Current database: examdb
Current user: root@localhost
SSL: Not in use
Using delimiter: ;
Server version: 4.1.14-nt
Protocol version: 10
Connection: localhost via TCP/IP
Server characterset: utf8
Db characterset: utf8
Client characterset: latin1
Conn. characterset: latin1
TCP port: 3306
Uptime: 4 hours 47 min 25 sec
テーブル:(コマンドプロンプトからは文字化けせず取得できます)
+--------+----------+-------------+
| dep_id | dep_name | dep_manager |
+--------+----------+-------------+
| 1 | 漢 | 中居正広 |
+--------+----------+-------------+
DAOでは、ResultSetオブジェクトのgetString()メソッドを使ってdep_nameを取得しようとしています。
String str=myResultSet.getString("dep_name");
あるWeb(http://ux01.so-net.ne.jp/~kikuta/jdbcnote/jdbc6_1.html)に、getString()は取得した文字列のバイトシーケンスの各頭に0x00を付加したものを返してくるとあったので、実際にこれをcharAt()を使って出力してみたところ
System.out.printf("0x%04X 0x%04X",str.charAt(0),str.charAt(1));
→0x0160 0x00BF
が返ってきました。
疑問1
"漢"のShift-JISは 0x8ABF なのでWebの説明どおりならば 0x008A と 0x00BF が返ってくるはずなのが、なぜ 0x0160 という頭に 0x00 をつけたものとは程遠いものが戻ってくるのでしょう?(後ろのバイトは、稀なケースを除いてほぼ頭に 0x00 がついてくるようです)
疑問1のことが解決し、仮に 0x008A,0x00BF が戻ってきたとして、そのWebの説明によると、「このように頭に0x00が付加されおかしなことになるので、これを次の式を使って元の 0x8ABF に戻す」とあります。
str.getBytes("8859_1")
そしてこの戻したものを
String(byte[] b, String charsetName)
のStringコンストラクタを使って "漢" の文字を復元する、というのです。
new String(str.getBytes("8859_1"),"SJIS");
疑問2
byte[] を返すgetBytes() を使って、なぜ int である 0x8ABF に戻すなんていうことができるのでしょう?
一方、私は試しにJavaアプリの中だけで
testStr="漢";
byte b[]=testStr.getBytes();
System.out.printf("%X %X\n",b[0],b[1]);
System.out.println(new String(b,"Windows-31J"));
System.out.print(Integer.toHexString((int)b[0]));
というのを出力してみました。結果は
8A BF
漢
ffffff8a
となりました。
疑問3
この実験で出てきた0x8A 0xBF は、0x008A 0x00BF と同じことですよね?それを new String() のbyte[]コンストラクタ引数に指定して、このように "漢" の字を作れています。それならば、なぜそもそも getString("dep_name") で返ってきた 0x008A 0x00BF をわざわざ 0x8ABF に戻すという処理が必要なのでしょうか。
疑問4
同じb[0]を表しているのに、なぜかたや 8A、かたや ffffff8a なのでしょう?これらはそれぞれ10進 138、-118 と、まったく違う数値です。どちらが本当の値なのでしょうか。138はintなので、ffffff8aのほうだと思うのですが…
疑問5
そもそも 0x008A 0x00BF にしろ 0x8ABF にしろいずれも int です。疑問4とも絡んできますが、なぜ上記のb[]に代入できたのかコンストラクタ引数に指定できたのか、不思議です。0x8ABFなんていう byte をはるかに超えた値をコンストラクタ引数に指定するとしているWebの説明も理解できません。
疑問6
MySQLには冒頭のcharsetsetを変更する方法があるそうです。このcharctersetが今回の文字化けに影響しているのかどうかもよく分からないのですが、取りあえず変更してみようにもその方法が分かりません。Webには my.ini を変更するとも my.cnf をいじるともあるのですが、my.ini はいじっても何も変わらないし、my.cnf はファイル自体がありません。
分からないことだらけなのですが、どうぞよろしくお願いします。