- PR -

DBの値を取り出す際の文字化けについて

投稿者投稿内容
Java使い
常連さん
会議室デビュー日: 2006/08/16
投稿数: 22
投稿日時: 2006-09-03 00:57
○事象:
DBから値を取り出すと文字化けしている。
tomcat、MySQLは同一マシンで稼働しており、文字コードはutf8にしているつもりです。
DB設定、tomcatからDBへの接続設定など見直したのですが、原因がわかりません。
他に確認すべき個所等あれば、ご教授願えないでしょうか。

○環境:
Linux FedoraCore5
tomcat 5.5.17
JDK 1.5.0_07-b03
MySQL 5.0.22

○DB値を取得するJavaロジック
InitialContext ic = new InitialContext();
DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/MySQLXoops");
Connection con = ds.getConnection();
Statement stmt = con.createStatement();
String sql = "SELECT * FROM xoops_users";
ResultSet rs = stmt.executeQuery(sql);
int user_id = 0;
while(rs.next()){
String uname = rs.getString("uname");・・・・・(※)
user_id = rs.getInt("uid");
if (uname.equals(villagerName)){
flag = true;
break;
}
}

※のunameを標準出力すると文字化けしています。
文字化けの仕方は、このような具合です。
\A\1\E\a!?\¶
これを確認したのもutf-8エンコーディングのコンソール上です。

※の部分を
String uname = new String(rs.getString("uname").getBytes("8859_1"));
このようにしてみてもだめでした。
この時は
・・・・・
のように化けています。

○tomcat設定
・/usr/share/tomcat5/conf/Catalina/localhost/コンテキスト名.xml
<Context docBase="コンテキスト名" path="/コンテキスト名" reloadable="true" source="org.eclipse.jst.j2ee.server:コンテキスト名">
<Resource
name="jdbc/MySQLXoops"
auth="Container"
type="javax.sql.DataSource"
username="ユーザ名"
password="パスワード"
driverClassName="org.gjt.mm.mysql.Driver"
url="jdbc:mysql:///xoops?useUnicode=true&amp;characterEncoding=utf8"/>
</Context>

○DB設定:
xoopsという名のデータベース内にxoops_usersテーブルがあります
mysql> status;

Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8


mysql> show full columns from xoops_users;
+-----------------+-----------------------+-----------------+------+-----+-----------+----------------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+-----------------+-----------------------+-----------------+------+-----+-----------+----------------+---------------------------------+---------+
| uid | mediumint(8) unsigned | NULL | NO | PRI | NULL | auto_increment | select,insert,update,references | |
| name | varchar(60) | utf8_general_ci | NO | | NULL | | select,insert,update,references | |
| uname | varchar(25) | utf8_general_ci | NO | MUL | NULL | | select,insert,update,references | |



mysql> show create database xoops;
+----------+----------------------------------------------------------------+
| Database | Create Database |
+----------+----------------------------------------------------------------+
| xoops | CREATE DATABASE `xoops` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+----------------------------------------------------------------+
Java使い
常連さん
会議室デビュー日: 2006/08/16
投稿数: 22
投稿日時: 2006-09-03 01:15
追加情報です。

JDBCは以下のものです。解凍したjarファイルをcommon/libに配備しています。
http://dev.mysql.com/downloads/connector/j/5.0.html

nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-09-03 12:43
引用:

Java使いさんの書き込み (2006-09-03 00:57) より:
String uname = new String(rs.getString("uname").getBytes("8859_1"));
このようにしてみてもだめでした。



getString()ではなく、getBytes()を使ってどういうデータが送られてきているかを
確認されてはいかがでしょうか。
生のバイト列を各種エンコードしたバイト列と比べてみれば何かわかるかも。

少なくともUTF-8にしているつもりだけど設定できていないのかどうかを
確認することはできますよね?
Java使い
常連さん
会議室デビュー日: 2006/08/16
投稿数: 22
投稿日時: 2006-09-03 16:24
(※)の部分をこのようにしてみました。
byte[] uname = rs.getBytes("uname");
for (byte b:uname){
 System.out.print(Integer.toHexString(b) + " ");
}

出力結果:
ffffffc2 ffffffa5 ffffffc3 ffffff86 ffffffc2 ffffffa5 ffffffc2 ffffffb9 ffffffc2 ffffffa5 ffffffc3 ffffff88

中身には「テスト」といれているつもりです。1文字が4byteになってる?
UTF8は3byteだったような…。
取り急ぎ報告です。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2006-09-03 17:13
引用:

Java使いさんの書き込み (2006-09-03 16:24) より:
(※)の部分をこのようにしてみました。
byte[] uname = rs.getBytes("uname");
for (byte b:uname){
 System.out.print(Integer.toHexString(b) + " ");
}

出力結果:
ffffffc2 ffffffa5 ffffffc3 ffffff86 ffffffc2 ffffffa5 ffffffc2 ffffffb9 ffffffc2 ffffffa5 ffffffc3 ffffff88

中身には「テスト」といれているつもりです。1文字が4byteになってる?
UTF8は3byteだったような…。
取り急ぎ報告です。



そりゃ、byteをintにキャストしてるのですから。
0〜7fまではそのまま表示、80〜ffまでは上位3byteがfで埋まって
表示されることでしょう。
コード:
String str = Integer.toHexString(b + 0x100);
System.out.print(str.substring(str.length()-2));


みたいな工夫は必要です。
もっとスマートに書く方法もありそうですけどね。

さて、問題の本質は
c2, a5, c3, 86, c2, a5, c2, b9, c2, a5, c3, 88
というバイト列は何者なのかということですが。
DBに入っているデータはどういったものでしたか?
その文字列をいろいろなエンコードで変換したバイト列と
見比べるとなにかわかるかもしれませんね。
Java使い
常連さん
会議室デビュー日: 2006/08/16
投稿数: 22
投稿日時: 2006-09-03 17:39
引用:

そりゃ、byteをintにキャストしてるのですから。
0〜7fまではそのまま表示、80〜ffまでは上位3byteがfで埋まって
表示されることでしょう。



1文字が4byteと書いたのは、
「テ」が c2, a5, c3, 86の4つのbyte列
「ス」が c2, a5, c2, b9の4つのbyte列
「ト」が c2, a5, c3, 88の4つのbyte列
で表現されているという意味です。
ff埋めのことではなかったのですが、わかりにくくてすいません。

引用:

さて、問題の本質は
c2, a5, c3, 86, c2, a5, c2, b9, c2, a5, c3, 88
というバイト列は何者なのかということですが。
DBに入っているデータはどういったものでしたか?


前投稿にも書いたのですが、「テスト」といれているつもりです。

「テスト」は本来、
E3 83 86、E3 82 B9、 E3 83 88
とならなければならないようです。

なぜかそれぞれの文字の最後のbyte列「86」、「B9」、「88」だけは合っているということはわかりました。さらに調べます。

[ メッセージ編集済み 編集者: Java使い 編集日時 2006-09-03 17:45 ]
coasm
大ベテラン
会議室デビュー日: 2001/11/26
投稿数: 237
投稿日時: 2006-09-03 17:49
引用:

「テ」が c2, a5, c3, 86の4つのbyte列
「ス」が c2, a5, c2, b9の4つのbyte列
「ト」が c2, a5, c3, 88の4つのbyte列



「テスト」のEUCコード a5 c6 a5 b9 a5 c8 を 0xa5c6 0a5b9 0xa5c8 という
Unicodeだとみなして UTF-8 にエンコードすると、そういうバイト列になります。

EUCで書き込んだデータをUTF-8で読み出しているということは、ありませんか?
Java使い
常連さん
会議室デビュー日: 2006/08/16
投稿数: 22
投稿日時: 2006-09-03 19:28
引用:

「テスト」のEUCコード a5 c6 a5 b9 a5 c8 を 0xa5c6 0a5b9 0xa5c8 という
Unicodeだとみなして UTF-8 にエンコードすると、そういうバイト列になります。

EUCで書き込んだデータをUTF-8で読み出しているということは、ありませんか?


なるほど…。
DBには「テスト」をUTF8エンコードしたバイト列が格納されているのではなく、
「テスト」のEUCコードをUTF8にエンコードしたバイト列が格納されているということになるのでしょうか…。

格納の仕方に問題がありそうですが、今からその部分を変更することは難しいのです。
読み出しの仕方によって解決できるのでしょうか。

スキルアップ/キャリアアップ(JOB@IT)