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 を利用することでカバーできそうな気配です。
サーブレットからデータ操作する場合は、フォームによるデータの受け渡し部分で適切なエンコードを指定して文字列を取り扱うことに注意すれば、あとはこのドキュメントに書いてあることかれていることが適用できるはずです。
次は実際にデータをデータベースに対して格納してみます。
データベースには、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');
Oracle 8.1.6 を用いて行ったテストと同じことを、8.0.5に対しても行ってみました。Databaseに格納してあるコードの文字と取得した文字データが異なっていたものを表2に示します。
表を眺めると泣きそうになりそうです。幸い 8.1.6 では支障ないレベルで日本語を扱えますので、8.0.5 には近づかないようにするか、制限事項としてしまう割り切りが必要なようです。
Oracle 8.0.6 と、Oracle 8.1.6 に対してテストを行ってみましたが、Windows版 Oracle 8.0.5 の場合に近いものがあります。ただ、これは Unicode - EUC のマッピングによる制約から来ているかと思われますので、回避は難しそうです。→表3
今回のテストに利用した Javaのソースファイルを公開しておきます。実際に利用される場合は、5行目付近の データベースサーバに対する URL や、ユーザ名、パスワードを適切なものに変更してください。
詳細はソース自体を参照してください。
Dbtest.java : Dbtest.java
他のデータベースサーバに対する結果など、フィードバックいただければ幸いです。