■Javaによるデータベース操作 - 日本語データの取り扱い

2001, 08 March
January 20, 2003 (関連URL追加)

Javaを使ってデータベースアクセスを行う際、留意すべき点についてまとめてみました。 このテストは、Windows 2000上で、Sun の Java 1.3.0 を用いて行っています。Java 1.2より古い VM では、デフォルトエンコーディングが異なっているなどの話も聞きますので、これから Javaを利用してデータベース操作を行う場合には、なるべく最新のものを利用されることを強くお勧めします。

まず、Unicodeから MS932 と SJIS の両エンコードにて byte配列を得た時、そのマッピング結果が異なる文字の一覧を表1に示します。
MS932では、期待されているであろう結果が得られているが、SJISでは '3F' つまり '?' という結果になっているものが数多くあります。この時点で SJIS については忘れてしまいたくなるのですが、データベースサーバによっては SJISのマッピングになってしまうものもあるようですので、注意が必要です。
さて、この表中で SJIS の結果に着目します。'3F'になっているものは利用不可ということで切り捨ててしまわざるを得ませんが

[?],2016,3F,8161
[?],2212,3F,817C

この2つは様子が違います。最初は '?' のマッピングが異なっているのかと思ったのですが、Unicodeの 2016、2012 はそれぞれ '‖'(DOUBLE VERTICAL LINE)、'−'(MINUS SIGN) であり、SJISのコードでは 8161(‖)、817C(−) で一致しています。
では、MS932 では、8161(‖)、817C(−) が 何処にマッピングされているかと調べてみると、Unicode の 2225 (PARALLEL TO)、FF0D (FULLWIDTH HYPHEN-MINUS) にマッピングされています。
# この表自体が MS932 での出力なので、オリジナルの文字が [?] と
# なってしまっていることが混乱の一因でした。

従って
SJIS のときは
[‖],2016
[−],2212

MS932のときは
[‖],2225
[−],ff0d

にマッピングされるということをおさえておけばOKです。
MS932のF040から[・]が並んでいるのはこの領域は外字で割り当てられる箇所で、ここが Unicodeの \uE000に対してマッピングされているので、外字についても MS932 を利用することでカバーできそうな気配です。

サーブレットからデータ操作する場合は、フォームによるデータの受け渡し部分で適切なエンコードを指定して文字列を取り扱うことに注意すれば、あとはこのドキュメントに書いてあることかれていることが適用できるはずです。

◇ オラクルデータベースサーバ ver 8.1.6 の場合

次は実際にデータをデータベースに対して格納してみます。
データベースには、Unicodeのコード と、文字そのものを 格納していき、後からデータを読み出した際に、Unicodeのコードが指している文字と、データベースから得た文字が一致しているかどうかで整合性を調べることにしました。
以下がその結果です。

Databaseに格納してあるコードの文字と取得した文字データが異なっていたもの
Unicode,文字,取得した文字,取得した文字のコード
a2,¢,¢,ffe0
a3,£,£,ffe1
a5,\,\,5c
ab,≪,?,ff1f
ac,¬,¬,ffe2
af, ̄,?,ff1f
b5,μ,?,ff1f
b7,・,・,30fb
b8,,,?,ff1f
bb,≫,?,ff1f
2016,?,‖,2225
203e,~,?,ff1f
2212,?,−,ff0d
3094,ヴ,?,ff1f
ff5e,〜,?,301c

データベースから取得した文字が '?'(\uff1f) になってしまっているものは、救えないです。
データベースへの insert文を実行する前に、これらのコードがあった場合は 適当なコードに置き換えてやり、データベースから取得した際 元に戻すことで回避できそうですが、それほど重要な文字では無いと思うので今回は省略します。
なお '~' (\u203e)、'ヴ'(\u3094) については、通常 \u007e、\u30f4 になるかと思いますので、気にしなくても大丈夫だとは思いますが、'~' については http://www.unicode.org/Public/MAPPINGS/EASTASIA/JIS/SHIFTJIS.TXT にて

0x7E	0x203E	# OVERLINE

と書かれているので、データベースへの挿入前に \u203e から \u007e への replace をかけた方が良いかもしれません。
さて、残るは、以下のものです。

a2,¢,¢,ffe0
a3,£,£,ffe1
a5,\,\,5c
ac,¬,¬,ffe2
b7,・,・,30fb
2016,?,‖,2225
2212,?,−,ff0d
ff5e,〜,?,301c

殆どのものは表示できているので \uff5e だけ留意すれば良いでしょう。
取得した文字列に対して以下のコードを一度 実行してやれば、Windows(MS932)環境であれば幸せになれるはずです。

str = str.replace('\u301c', '\uff5e');

◇ オラクルデータベースサーバ ver 8.0.5 の場合

Oracle 8.1.6 を用いて行ったテストと同じことを、8.0.5に対しても行ってみました。Databaseに格納してあるコードの文字と取得した文字データが異なっていたものを表2に示します。
表を眺めると泣きそうになりそうです。幸い 8.1.6 では支障ないレベルで日本語を扱えますので、8.0.5 には近づかないようにするか、制限事項としてしまう割り切りが必要なようです。

◇ オラクルデータベースサーバ on Solaris の場合

Oracle 8.0.6 と、Oracle 8.1.6 に対してテストを行ってみましたが、Windows版 Oracle 8.0.5 の場合に近いものがあります。ただ、これは Unicode - EUC のマッピングによる制約から来ているかと思われますので、回避は難しそうです。→表3

◇ テスト用 Javaプログラム

今回のテストに利用した Javaのソースファイルを公開しておきます。実際に利用される場合は、5行目付近の データベースサーバに対する URL や、ユーザ名、パスワードを適切なものに変更してください。
詳細はソース自体を参照してください。
Dbtest.java : Dbtest.java

他のデータベースサーバに対する結果など、フィードバックいただければ幸いです。

関連URL: