JAVA PRESS Vol.8
『Javaデータベース技法と日本語事情』
-日本語処理上の問題とその解決策-
入校バージョン (1999/07/26版)

伊賀みどり (http://www003.upp.so-net.ne.jp/midori/midosoft.html)

  • タイトル : JAVA PRESS Vol.8 入校原稿 : 『Javaデータベース技法と日本語事情』
  • 説明 : JAVA PRESS Vol.8 『Javaデータベース技法と日本語事情』 -日本語処理上の問題とその解決策- : 入校原稿そのまま
  • キーワード: Java,日本語,文字化け,文字コード,エンコード,エンコーディング,Oracle,SQLServer

JAVA PRESSサポートページへ戻る

前提
はじめに

最近、Javaは 更にブームになってきたようで 世間でもさまざまな事例などが紹介されるようになってきました。特にここ最近目立つのが、データベースと連動するシステムをJavaで作ったという事例が
日本でも少なからず紹介されるようになってきた点です。一方、Java自身も 日ごろからの猛烈なバージョンアップの末 最新版のJava2においては 網羅的な機能の装備と各国語対応(含む日本語)を済ませたと言われています。額面通り受け取ると データベースにおいても日本語がすんなり利用できるように理解&期待できます。本当なんでしょうか?

他方 Java単体(データベースなどを含まないという意味) としては、印刷関連を除くと 比較的安定しているように感じられます。また世間でもそのように認識されているように思われます。そうだとすると いよいよあとはデータベースさえ使いモノになれば 現実的な開発の際の選択肢として Javaが選ばれる時代が到来することになります。

本稿では、Windows用のJ2SDK1.2.2を使って Oracle8・SQLServer6.5・Accessデータベース に対するデータベースアクセスを取り上げ、データベース最初の一歩・データベース以前のJavaの日本語事情・データベースにおける日本語導通調査の実施および考察・そして私の経験した その他の注意点 などを取り上げて行き、データベース技法の日本語事情を 少し『厳しく』検証していきたく思います。

本稿で扱うデータベース アクセス手法

Javaからのデータベースアクセスは JDBCを利用することが標準の手法となっています。とはいえ JDBCを利用する上であっても、実際のプログラミングスタイルとしては 主なものでも下記のように数パターンが検討されることが多いようです。

  1. JDK の JDBC-API を直接利用する
    JavaのAPIで定義されているJDBCそれ自身です。
  2. JavaRADのデータベース部品を利用する
    JBuilderなら JBCL というように、JDBCをより抽象化したソフト部品を 各JavaRADベンダーが出しています。
  3. SQLJ
    主なデータベースベンダーなどが集まって作った 埋め込み型SQL文記述方法です。JDBC-APIを直接利用するのに比べ 簡潔な記述を実現します。プリコンパイラ方式で これを通常のJavaソースコードに変換できるのだそうです。しかし、JavaRADによっては、SQLJを扱えないものも存在します。

なお、本稿では (1) の 生JDBC-API を対象とします。

本稿で扱うソフトウェア環境

Javaは Windows版 J2SDK 1.2.2 を利用します。
データベースは 下記のソフトおよびJDBCドライバを利用します。

データベース JDBCドライバ タイプ
Oracle8 WorkGroupServer for WindowsNT 8.0.4 Oracle JDBC Driver 8.0.5.0.4
(日本オラクルからダウンロード可能)
(http://www.oracle.co.jp/)
注: このドライバはJava2はサポート外
Type4
Microsoft SQLServer6.5 (Intel) + SP5a JDBC-ODBC Bridge (J2SDKに含まれる)
または
拙作 JDBC-ODBC Bridge (後述)

ODBCドライバは 下記に含まれるものを利用
Microsoft Data Access Components 2.0
(WindowsNT4.0SP4に含まれます)
Type1
Microsoft Access ODBC ドライバ 同上 同上

検証に利用したマシンのスペックの概要

フロンティア神代 Frontier FBX333C/98
[CPU] Intel Celeron 333MHz (128KBキャッシュ)
[メモリ] S-DRAM 128MB (8ns)
[OS] Microsoft WindowsNT Workstation 4.0J + SP4

データベースおよびJDBC環境のセットアップについて

データベースのセットアップについて、簡単に説明を加えさせていただきます。というのも、素のままの環境では JDBC のアクセスが出来ない場合があるからなのです。

  1. Oracle8
  2. SQLServer6.5
  3. Microsoft Access ODBC ドライバ
データベース以前の Javaにおける日本語

本稿の最初の方で 『Java2 になり各国語対応を終え』 などと書きましたが、実際のところ どうなのでしょう。データベースの話に入るのに先立ち まず Java2 (J2SDK 1.2.2) における日本語の扱いを調べてみます。まず C++のプログラムである <TestChar/main.cpp> を用いて シフトJIS一覧ファイル <TestChar.txt> を作成してみます。全てのシフトJISを漏れなく網羅しているかどうかは疑問ですが、ほとんど全てのシフトJISを 集めることには成功しているようです。(というよりシフトJIS領域以外も一覧に含めて取ってきています。)
次に このファイルを Javaのプログラム <EncodeDecode.java> を用いて、シフトJISファイルを読み込んで すぐに書き出します。読み込み 書き込みには java.io.InputStreamReader , java.io.OutputStreamWriter を用いました。このため Javaの仕組みを使って シフトJIS→UNICODE 変換 を行いそれをそのままUNICODE→シフトJIS 変換していることになります。
『なぜこんな事を』 と思われるかもしれません。だいたい パッと考えた範囲だと 可逆変換して元通りに戻りそうなものなのですが、、、これが試してみると 元通りに戻らない文字が結構あるのです。戻らなかったものの結果は <EncodeDecode.txt> です。シフトJIS 表現で、8740: ?@ などの機種依存文字列 や ed40: ?\ 以降の外字領域が 元に戻りませんでした。これらは予想していたのですが、8160: 〜 8161: ‖ 817c: − などの 『ふつ〜』 の領域が 元に戻りませんでした。ショックです。
これらは UNICODE 上に 対応する文字が無いなどの理由と思われますが、私の身近に UNICODE に関する詳細な資料が無いので不明です。
しかし 少なくとも これら文字が Javaにおいて扱えないということを 事前に把握しておくことは非常に重要だと考えます。これらの日本語に関する不思議な問題は 設定などにより調整することは可能なのかもしれませんが、少なくとも デフォルトで 私の環境においては、上記のような結果になってしまいます。
(ちょっと困ったものですね)

EncodeDecode.java

import java.io.*;

public class EncodeDecode
{
        public static void main(String[] args)
        {
                try{
                        System.out.println("日本語テスト: 日本語エンコード&デコードテスト開始");

                        String strSeparator=System.getProperty("file.separator");
                        BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream(".."+strSeparator+"TestChar"+strSeparator+"TestChar.txt"),"SJIS"));
                        BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("EncodeDecode.out")));

                        for(String strRead=reader.readLine();strRead!=null;strRead=reader.readLine())
                        {
                                System.out.println(strRead);
                                writer.write(strRead);
                                writer.newLine();
                        }

                        writer.flush();
                        writer.close();
                        reader.close();

                        System.out.println("日本語テスト: 日本語エンコード&デコードテスト終了");
                }catch(IOException ex){
                        System.out.println("日本語テスト: 日本語エンコード&デコードテスト");
                        System.out.println(ex.toString());
                }
        }
}

EncodeDecode.txt
(作者注: これらは文字コードが文字コードだけに Windowsパソコン以外では表示できないものが多いです)

SJIS→UNICODE→SJISして うまく変換されなかったもの。
8160: 〜
8161: ‖
817c: −
8740: ?@
8741: ?A
8742: ?B
8743: ?C
8744: ?D
8745: ?E
8746: ?F
8747: ?G
8748: ?H
8749: ?I
874a: ?J
874b: ?K
874c: ?L
874d: ?M
874e: ?N
874f: ?O
8750: ?P
8751: ?Q
8752: ?R
8753: ?S
8754: ?T
8755: ?U
8756: ?V
8757: ?W
8758: ?X
8759: ?Y
875a: ?Z
875b: ?[
875c: ?\
875d: ?]
875f: ?_
8760: ?`
8761: ?a
8762: ?b
8763: ?c
8764: ?d
8765: ?e
8766: ?f
8767: ?g
8768: ?h
8769: ?i
876a: ?j
876b: ?k
876c: ?l
876d: ?m
876e: ?n
876f: ?o
8770: ?p
8771: ?q
8772: ?r
8773: ?s
8774: ?t
8775: ?u
877e: ?~
8780: ??
8781: ??
8782: ??
8783: ??
8784: ??
8785: ??
8786: ??
8787: ??
8788: ??
8789: ??
878a: ??
878b: ??
878c: ??
878d: ??
878e: ??
878f: ??
8790: ≒
8791: ≡
8792: ∫
8793: ??
8794: ??
8795: √
8796: ⊥
8797: ∠
8798: ??
8799: ??
879a: ∵
879b: ∩
879c: ∪
ed40: ?\
ed41: ?]
ed42: ?^
ed43: ?_
ed44: ?`
ed45: ?a
ed46: ?b
ed47: ?c
ed48: ?d
ed49: ?e
ed4a: ?f
ed4b: ?g
ed4c: ?h
ed4d: ?i
ed4e: ?j
ed4f: ?k
ed50: ?l
ed51: ?m
ed52: ?n
ed53: ?o
ed54: ?p
ed55: ?q
ed56: ?r
ed57: ?s
ed58: ?t
ed59: ?u
ed5a: ?v
ed5b: ?w
ed5c: ?x
ed5d: ?y
ed5e: ?z
ed5f: ?{
ed60: ?|
ed61: ?}
ed62: ?~
ed63: ??
ed64: ??
ed65: ??
ed66: ??
ed67: ??
ed68: ??
ed69: ??
ed6a: ??
ed6b: ??
ed6c: ??
ed6d: ??
ed6e: ??
ed6f: ??
ed70: ??
ed71: ??
ed72: ??
ed73: ??
ed74: ??
ed75: ??
ed76: ??
ed77: ??
ed78: ??
ed79: ??
ed7a: ??
ed7b: ??
ed7c: ??
ed7d: ??
ed7e: ??
ed80: ??
ed81: ??
ed82: ??
ed83: ??
ed84: ??
ed85: ?。
ed86: ?「
ed87: ?」
ed88: ?、
ed89: ?・
ed8a: ?ヲ
ed8b: ?ァ
ed8c: ?ィ
ed8d: ?ゥ
ed8e: ?ェ
ed8f: ?ォ
ed90: ?ャ
ed91: ?ュ
ed92: ?ョ
ed93: ?ッ
ed94: ?ー
ed95: ?ア
ed96: ?イ
ed97: ?ウ
ed98: ?エ
ed99: ?オ
ed9a: ?カ
ed9b: ?キ
ed9c: ?ク
ed9d: ?ケ
ed9e: ?コ
ed9f: ?サ
eda0: ?シ
eda1: ?ス
eda2: ?セ
eda3: ?ソ
eda4: ?タ
eda5: ?チ
eda6: ?ツ
eda7: ?テ
eda8: ?ト
eda9: ?ナ
edaa: ?ニ
edab: ?ヌ
edac: ?ネ
edad: ?ノ
edae: ?ハ
edaf: ?ヒ
edb0: ?フ
edb1: ?ヘ
edb2: ?ホ
edb3: ?マ
edb4: ?ミ
edb5: ?ム
edb6: ?メ
edb7: ?モ
edb8: ?ヤ
edb9: ?ユ
edba: ?ヨ
edbb: ?ラ
edbc: ?リ
edbd: ?ル
edbe: ?レ
edbf: ?ロ
edc0: ?ワ
edc1: ?ン
edc2: ?゙
edc3: ?゚
edc4: ??
edc5: ??
edc6: ??
edc7: ??
edc8: ??
edc9: ??
edca: ??
edcb: ??
edcc: ??
edcd: ??
edce: ??
edcf: ??
edd0: ??
edd1: ??
edd2: ??
edd3: ??
edd4: ??
edd5: ??
edd6: ??
edd7: ??
edd8: ??
edd9: ??
edda: ??
eddb: ??
eddc: ??
eddd: ??
edde: ??
eddf: ??
ede0: ??
ede1: ?@
ede2: ?A
ede3: ?B
ede4: ?C
ede5: ?D
ede6: ?E
ede7: ?F
ede8: ?G
ede9: ?H
edea: ?I
edeb: ?J
edec: ?K
eded: ?L
edee: ?M
edef: ?N
edf0: ?O
edf1: ?P
edf2: ?Q
edf3: ?R
edf4: ?S
edf5: ?T
edf6: ?U
edf7: ?V
edf8: ?W
edf9: ?X
edfa: ?Y
edfb: ?Z
edfc: ?[
ee40: ?\
ee41: ?]
ee42: ?^
ee43: ?_
ee44: ?`
ee45: ?a
ee46: ?b
ee47: ?c
ee48: ?d
ee49: ?e
ee4a: ?f
ee4b: ?g
ee4c: ?h
ee4d: ?i
ee4e: ?j
ee4f: ?k
ee50: ?l
ee51: ?m
ee52: ?n
ee53: ?o
ee54: ?p
ee55: ?q
ee56: ?r
ee57: ?s
ee58: ?t
ee59: ?u
ee5a: ?v
ee5b: ?w
ee5c: ?x
ee5d: ?y
ee5e: ?z
ee5f: ?{
ee60: ?|
ee61: ?}
ee62: ?~
ee63: ??
ee64: ??
ee65: ??
ee66: ??
ee67: ??
ee68: ??
ee69: ??
ee6a: ??
ee6b: ??
ee6c: ??
ee6d: ??
ee6e: ??
ee6f: ??
ee70: ??
ee71: ??
ee72: ??
ee73: ??
ee74: ??
ee75: ??
ee76: ??
ee77: ??
ee78: ??
ee79: ??
ee7a: ??
ee7b: ??
ee7c: ??
ee7d: ??
ee7e: ??
ee80: ??
ee81: ??
ee82: ??
ee83: ??
ee84: ??
ee85: ?。
ee86: ?「
ee87: ?」
ee88: ?、
ee89: ?・
ee8a: ?ヲ
ee8b: ?ァ
ee8c: ?ィ
ee8d: ?ゥ
ee8e: ?ェ
ee8f: ?ォ
ee90: ?ャ
ee91: ?ュ
ee92: ?ョ
ee93: ?ッ
ee94: ?ー
ee95: ?ア
ee96: ?イ
ee97: ?ウ
ee98: ?エ
ee99: ?オ
ee9a: ?カ
ee9b: ?キ
ee9c: ?ク
ee9d: ?ケ
ee9e: ?コ
ee9f: ?サ
eea0: ?シ
eea1: ?ス
eea2: ?セ
eea3: ?ソ
eea4: ?タ
eea5: ?チ
eea6: ?ツ
eea7: ?テ
eea8: ?ト
eea9: ?ナ
eeaa: ?ニ
eeab: ?ヌ
eeac: ?ネ
eead: ?ノ
eeae: ?ハ
eeaf: ?ヒ
eeb0: ?フ
eeb1: ?ヘ
eeb2: ?ホ
eeb3: ?マ
eeb4: ?ミ
eeb5: ?ム
eeb6: ?メ
eeb7: ?モ
eeb8: ?ヤ
eeb9: ?ユ
eeba: ?ヨ
eebb: ?ラ
eebc: ?リ
eebd: ?ル
eebe: ?レ
eebf: ?ロ
eec0: ?ワ
eec1: ?ン
eec2: ?゙
eec3: ?゚
eec4: ??
eec5: ??
eec6: ??
eec7: ??
eec8: ??
eec9: ??
eeca: ??
eecb: ??
eecc: ??
eecd: ??
eece: ??
eecf: ??
eed0: ??
eed1: ??
eed2: ??
eed3: ??
eed4: ??
eed5: ??
eed6: ??
eed7: ??
eed8: ??
eed9: ??
eeda: ??
eedb: ??
eedc: ??
eedd: ??
eede: ??
eedf: ??
eee0: ??
eee1: ?@
eee2: ?A
eee3: ?B
eee4: ?C
eee5: ?D
eee6: ?E
eee7: ?F
eee8: ?G
eee9: ?H
eeea: ?I
eeeb: ?J
eeec: ?K
eeef: ?@
eef0: ?A
eef1: ?B
eef2: ?C
eef3: ?D
eef4: ?E
eef5: ?F
eef6: ?G
eef7: ?H
eef8: ?I
eef9: ¬
eefa: ?U
eefb: ?V
eefc: ?W
fa40: ?@
fa41: ?A
fa42: ?B
fa43: ?C
fa44: ?D
fa45: ?E
fa46: ?F
fa47: ?G
fa48: ?H
fa49: ?I
fa4a: ?T
fa4b: ?U
fa4c: ?V
fa4d: ?W
fa4e: ?X
fa4f: ?Y
fa50: ?Z
fa51: ?[
fa52: ?\
fa53: ?]
fa54: ¬
fa55: ?U
fa56: ?V
fa57: ?W
fa58: ??
fa59: ??
fa5a: ??
fa5b: ∵
fa5c: ?\
fa5d: ?]
fa5e: ?^
fa5f: ?_
fa60: ?`
fa61: ?a
fa62: ?b
fa63: ?c
fa64: ?d
fa65: ?e
fa66: ?f
fa67: ?g
fa68: ?h
fa69: ?i
fa6a: ?j
fa6b: ?k
fa6c: ?l
fa6d: ?m
fa6e: ?n
fa6f: ?o
fa70: ?p
fa71: ?q
fa72: ?r
fa73: ?s
fa74: ?t
fa75: ?u
fa76: ?v
fa77: ?w
fa78: ?x
fa79: ?y
fa7a: ?z
fa7b: ?{
fa7c: ?|
fa7d: ?}
fa7e: ?~
fa80: ??
fa81: ??
fa82: ??
fa83: ??
fa84: ??
fa85: ??
fa86: ??
fa87: ??
fa88: ??
fa89: ??
fa8a: ??
fa8b: ??
fa8c: ??
fa8d: ??
fa8e: ??
fa8f: ??
fa90: ??
fa91: ??
fa92: ??
fa93: ??
fa94: ??
fa95: ??
fa96: ??
fa97: ??
fa98: ??
fa99: ??
fa9a: ??
fa9b: ??
fa9c: ??
fa9d: ??
fa9e: ??
fa9f: ??
faa0: ??
faa1: ?。
faa2: ?「
faa3: ?」
faa4: ?、
faa5: ?・
faa6: ?ヲ
faa7: ?ァ
faa8: ?ィ
faa9: ?ゥ
faaa: ?ェ
faab: ?ォ
faac: ?ャ
faad: ?ュ
faae: ?ョ
faaf: ?ッ
fab0: ?ー
fab1: ?ア
fab2: ?イ
fab3: ?ウ
fab4: ?エ
fab5: ?オ
fab6: ?カ
fab7: ?キ
fab8: ?ク
fab9: ?ケ
faba: ?コ
fabb: ?サ
fabc: ?シ
fabd: ?ス
fabe: ?セ
fabf: ?ソ
fac0: ?タ
fac1: ?チ
fac2: ?ツ
fac3: ?テ
fac4: ?ト
fac5: ?ナ
fac6: ?ニ
fac7: ?ヌ
fac8: ?ネ
fac9: ?ノ
faca: ?ハ
facb: ?ヒ
facc: ?フ
facd: ?ヘ
face: ?ホ
facf: ?マ
fad0: ?ミ
fad1: ?ム
fad2: ?メ
fad3: ?モ
fad4: ?ヤ
fad5: ?ユ
fad6: ?ヨ
fad7: ?ラ
fad8: ?リ
fad9: ?ル
fada: ?レ
fadb: ?ロ
fadc: ?ワ
fadd: ?ン
fade: ?゙
fadf: ?゚
fae0: ??
fae1: ??
fae2: ??
fae3: ??
fae4: ??
fae5: ??
fae6: ??
fae7: ??
fae8: ??
fae9: ??
faea: ??
faeb: ??
faec: ??
faed: ??
faee: ??
faef: ??
faf0: ??
faf1: ??
faf2: ??
faf3: ??
faf4: ??
faf5: ??
faf6: ??
faf7: ??
faf8: ??
faf9: ??
fafa: ??
fafb: ??
fafc: ??
fb40: ?@
fb41: ?A
fb42: ?B
fb43: ?C
fb44: ?D
fb45: ?E
fb46: ?F
fb47: ?G
fb48: ?H
fb49: ?I
fb4a: ?J
fb4b: ?K
fb4c: ?L
fb4d: ?M
fb4e: ?N
fb4f: ?O
fb50: ?P
fb51: ?Q
fb52: ?R
fb53: ?S
fb54: ?T
fb55: ?U
fb56: ?V
fb57: ?W
fb58: ?X
fb59: ?Y
fb5a: ?Z
fb5b: ?[
fb5c: ?\
fb5d: ?]
fb5e: ?^
fb5f: ?_
fb60: ?`
fb61: ?a
fb62: ?b
fb63: ?c
fb64: ?d
fb65: ?e
fb66: ?f
fb67: ?g
fb68: ?h
fb69: ?i
fb6a: ?j
fb6b: ?k
fb6c: ?l
fb6d: ?m
fb6e: ?n
fb6f: ?o
fb70: ?p
fb71: ?q
fb72: ?r
fb73: ?s
fb74: ?t
fb75: ?u
fb76: ?v
fb77: ?w
fb78: ?x
fb79: ?y
fb7a: ?z
fb7b: ?{
fb7c: ?|
fb7d: ?}
fb7e: ?~
fb80: ??
fb81: ??
fb82: ??
fb83: ??
fb84: ??
fb85: ??
fb86: ??
fb87: ??
fb88: ??
fb89: ??
fb8a: ??
fb8b: ??
fb8c: ??
fb8d: ??
fb8e: ??
fb8f: ??
fb90: ??
fb91: ??
fb92: ??
fb93: ??
fb94: ??
fb95: ??
fb96: ??
fb97: ??
fb98: ??
fb99: ??
fb9a: ??
fb9b: ??
fb9c: ??
fb9d: ??
fb9e: ??
fb9f: ??
fba0: ??
fba1: ?。
fba2: ?「
fba3: ?」
fba4: ?、
fba5: ?・
fba6: ?ヲ
fba7: ?ァ
fba8: ?ィ
fba9: ?ゥ
fbaa: ?ェ
fbab: ?ォ
fbac: ?ャ
fbad: ?ュ
fbae: ?ョ
fbaf: ?ッ
fbb0: ?ー
fbb1: ?ア
fbb2: ?イ
fbb3: ?ウ
fbb4: ?エ
fbb5: ?オ
fbb6: ?カ
fbb7: ?キ
fbb8: ?ク
fbb9: ?ケ
fbba: ?コ
fbbb: ?サ
fbbc: ?シ
fbbd: ?ス
fbbe: ?セ
fbbf: ?ソ
fbc0: ?タ
fbc1: ?チ
fbc2: ?ツ
fbc3: ?テ
fbc4: ?ト
fbc5: ?ナ
fbc6: ?ニ
fbc7: ?ヌ
fbc8: ?ネ
fbc9: ?ノ
fbca: ?ハ
fbcb: ?ヒ
fbcc: ?フ
fbcd: ?ヘ
fbce: ?ホ
fbcf: ?マ
fbd0: ?ミ
fbd1: ?ム
fbd2: ?メ
fbd3: ?モ
fbd4: ?ヤ
fbd5: ?ユ
fbd6: ?ヨ
fbd7: ?ラ
fbd8: ?リ
fbd9: ?ル
fbda: ?レ
fbdb: ?ロ
fbdc: ?ワ
fbdd: ?ン
fbde: ?゙
fbdf: ?゚
fbe0: ??
fbe1: ??
fbe2: ??
fbe3: ??
fbe4: ??
fbe5: ??
fbe6: ??
fbe7: ??
fbe8: ??
fbe9: ??
fbea: ??
fbeb: ??
fbec: ??
fbed: ??
fbee: ??
fbef: ??
fbf0: ??
fbf1: ??
fbf2: ??
fbf3: ??
fbf4: ??
fbf5: ??
fbf6: ??
fbf7: ??
fbf8: ??
fbf9: ??
fbfa: ??
fbfb: ??
fbfc: ??
fc40: ?@
fc41: ?A
fc42: ?B
fc43: ?C
fc44: ?D
fc45: ?E
fc46: ?F
fc47: ?G
fc48: ?H
fc49: ?I
fc4a: ?J
fc4b: ?K

データベースにまずつなげるために

日本語を調査するプログラムの説明に先立ち 各データベースの接続文字列を簡単に紹介しておきます。
JDBC-API により データベースアクセスは標準化されていますが、データベースドライバの登録とデータベースへの接続に関しては、データベース毎に固有の 見慣れない記述が必要になります。慣れるまでは違和感の多い方もいらっしゃると思われるので、特に取り上げて説明します。

  1. ORACLE の場合
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","USER1","user1");
    【説明】
  2. SQLServer, Access の場合
    DriverManager.registerDriver(new sun.jdbc.odbc.JdbcOdbcDriver());
    Connection conn=DriverManager.getConnection("jdbc:odbc:test1","user1","user1");
    【説明】
日本語導通調査プログラム

前述『データベース以前の Javaにおける日本語』で驚かれた方・腰が引けた方もいらっしゃるかもしれませんが、これだけで済みませんで、データベースが絡むと もっと凄いことになってしまうのです。これを説明するために ちょっとしたテストプログラムを作成しました。

  1. 文字コード 文字データ だけを格納するための テーブルを作成する
  2. シフトJIS一覧ファイル <TestChar.txt> を読み込みながら INSERT する
  3. 文字コード順に SELECT をかけ、これをファイルに出力する
  4. 2 と 3 の内容の比較を行い、どのような差異が現れたかを調査する

なお Java自身のエンコード・デコードに起因する部分は除いて調査しました。

日本語導通調査プログラム結果: Oracleの場合

下記の3文字が 格納→取り出しを経て 元に戻りませんでした。
8191: ¢
8192: £
81ca: ¬
一方 下記の文字は Javaのエンコード・デコード変換で既に異常だったのにも関わらず Oracleを経由するとなぜか元通りに復元しました。
8160: 〜
なお、Oracle の場合には 特別に getString() が妙な挙動を行います。なぜか 取り出した文字列の後方に 意図しない空白が付け加えられてしまうのです。とりあえず Oracleの際の調査プログラムでは trim() をかけて この空白を除去しています。
なお、改めて確認しておきますが、Oracle JDBC Driver の今バージョンは Java2 はサポート外です。この点に 誤解の無いよう 特にお願いいたします。

日本語導通調査プログラム結果: SQLServer および Access の場合

SQLServer および Access は 同じ JDBC-ODBC Bridge を用いました。このためか結果も同一になりました。
下記の26 文字が 格納→取り出しを経て 元に戻りませんでした。
8140:   (全角スペースが 長さ0の文字列に変わってしまいます)
8191: ¢
8192: £
81ca: ¬
81cd: ∀
849f: ─
88ea: 一
8b48: 稀
8b49: 紀
8b56: 儀
8cbe: 言
8dc5: 最
8ec1: 蔀
8ef9: 需
91de: 退
9381: 刀
9664: 謀
9678: 堀
9773: 耀
986f: 椀
9a9b: 圀
9cb5: 愀
9cf6: 戀
9db3: 攀
e2c5: 簀
e586: 蜀
不思議なことに よく使いそうな文字が通りません :-) 全角スペースが消し飛ぶのも凄いですが、それ以外にも とても困る字が多数含まれています。この結果は 私の勘違いであって欲しいのですが、残念なことに そうではないようです。JDBCドライバが準備されていない&入手できないデータベースに対する接続には JDBC-ODBC Bridge を利用するのが どんどん一般的になって行くはずであるだけに残念です。
で、これを不思議に思い スクラッチでオープンソースな JDBC-ODBC Bridge を開発しました。

JDBC-ODBC Bridge の自作

前述のように、Java2 標準の JDBC-ODBC Bridge の日本語導通具合に耐え兼ねて、スクラッチからオープンソースな JDBC-ODBC Bridge を開発しました。情報源としては、参考文献*2 を利用しました。
開発したといっても 今回のテストプログラムや 参考文献*1 のサンプルの一部が通る程度の ものすごく手抜きな JDBC-ODBC Bridge です。UNICODE と SJIS との変換には String.getBytes("SJIS") などのJavaの最も標準的なコード変換をベースに開発しました。(と敢えて言うのがなぜかというと、標準の JDBC-ODBC Bridge は これとは別の仕組みを使ってコード変換を行っているからなのです。)
ということで、この自作した JDBC-ODBC Bridge を通した際の結果を見てみます。

『余談』
JDBC-ODBC Bridge を作ってみてわかったのですが、JDBCドライバの開発は ODBCドライバの開発より自明であることがわかりました。開発自身は明白で とても開発しやすかったのですが、反面 API の数が結構あるので 手数は多くかかるということもわかりました。

日本語導通調査プログラム結果: 拙作 JDBC-ODBC Bridge を経由した時の SQLServer の場合

文字は全て通りました。それに加え 下記の文字は Javaのエンコード・デコード変換で既に異常だったのにも関わらず
私の JDBC-ODBC Bridge を経由するとなぜか元通りに復元しました。
8160: 〜
8161: ‖
817c: −

日本語導通調査プログラム結果の考察

今まで述べてきたように、JDBC を利用した際の日本語具合には いろいろ問題があることがわかりました。特に本命と思っていた JDBC-ODBC Bridge の結果が思わしくなかったのは 非常に残念です。
しかし一方、拙作 JDBC-ODBC Bridge を経由した際の結果からわかるように、JDBCのカラクリ自身に 日本語を通さない欠陥があるわけではなく、むしろ個々のドライバの実装に 問題の火種があるようなのです。また、究極の解決方法として JDBC-ODBC Bridge を自作などすることにより これら日本語の通らない問題は打破できることもわかりました。

これからJDBCに手を染めてみようとされている方に、、、

今まで 日本語環境に関する話題に集中してきましたが、続いて それ以外の JDBC に関するコツやネタを 取り上げたいと思います。

  1. SQL文自身には 日本語を含めることができないことが多い。
    JavaおよびJDBCは 舶来ソフトゆえに SQL文自身には 日本語を含むことが出来ない場合が多いです。このため、テーブル名・項目名には 日本語が利用できないことになります。(無論 拙作JDBC-ODBC Bridge は SQL文にも日本語が通ります) 一方、INSERT などの値として 日本語が使えなくなるので、java.sql.PreparedStatement と パラメータ文字列 '?' の組み合わせを使うケースが多くなっていくと考えられます。(本稿の日本語導通調査プログラムも そのように書いております)
  2. データベースアクセスのプログラミングを標準化して、なるべくワンパターンでアクセスする
    比較的新しい開発環境を利用する場合のコツなのですが、Windows+ODBCなどの既存環境における通常の場合などの通常の場合に さらに加えて、アクセスの方法をワンパターン化しておくことが重要になってくると考えています。ワンパターン化して使い古すことにより、遭遇しなくても済むバグを見ることが少なくなりますし、記述方法自身に問題があった場合は その記述をワンパターンで 別の記述方法に置換することができるようになります。1. の現象もあることから、例えば java.sql.PreparedStatement を原則利用することにするなどの標準の作成などが出来るでしょう。
  3. サーバプログラミングを行う場合に特に重要なのですが、Oracle をマルチスレッド環境下において 数千行レベルのSELECTを行うと メモリ不足のエラーが発生して 引き続きカーソル異常などの障害が発生してしまう場合があります。これは JDK1.1.x と Oracle JDBC Driver 8.0.5.0.4 との組み合わせでは発生してしまうようです。(以前のバージョンのドライバでも発生) Statementをclose() してみたり いろいろ工夫しても駄目で、なかなかに悩ましいです。これが発生してしまう事から類推すると、コネクションプーリングなどの技法を、自分で実装あるいは実装されている サーバ製品では このエラーが起きてしまう恐れがあります。
    見た目の雰囲気としては、ガベージコレクションに処理されない 『産業廃棄物』のメモリのゴミが何らかの原因で発生して、これが起因してメモリ不足を発生しているように見えるのですが、、、。詳細は不明です。しかし システム開発の前に プロトタイピングしてテストしておくことをお勧めしますし、それにより回避可能な問題だと考えています。
  4. 3. と同様 サーバプログラミングを行う場合に特に重要なのですが、SQLServer6.5 を利用している際に、java.sql.PreparedStatementを任意個数作成して利用すると、tempdb に ストアドプロシージャが残ってしまう場合があります。これは JDBC や Java とは関係なく、 むしろ SQLServerの ODBCドライバの特徴なのですが、java.sql.PreparedStatement を作り出すたびに 内部的には ODBC-API の SQLPrepare() が呼ばれて、結果 tempdb の空容量が どんどん減っていってしまいます。このtempdbの容量圧迫は データベース接続を切断することにより はじめて開放されるようになっています。日本語を通すために java.sql.PreparedStatement は多用することになるでしょうから、この問題は影響が大きいです。
    これを回避するためには プログラムで 同一のSQL文に対し 一度だけ java.sql.PreparedStatementを作成し、以降 このjava.sql.PreparedStatement を使いまわすのが妥当な回避策のようです。(本稿の日本語導通調査プログラムも そのように書いております)
  5. 3. などの問題を回避するために、プロトタイプ作成などを行う際には、WindowsNT タスクマネージャなどのメモリの使用量がわかるツールを使って、常にメモリ使用量をチェックすることが重要だと思います。また、3. の現象は 大量データによってはじめて発生するので、テストの際には そういった限界のようなテストを実施することが重要になってくると思います。これは Javaが ガベージコレクションを行う言語ゆえに必要になってくる注意点だと思います。(メモリリークシンドロームよりは ずっと気が楽なんですけどね)
  6. 上記のようなことから、もし高い可用性が要求されるシステムをJavaを用いて書く場合には、プロセス分割を用いた縮退の仕組みを作り込むことが効果的だと考えています。これは Javaのメモリ管理がJavaVM単位であるので、ガベージコレクションに何かしら 意図とは違う動きなどがある場合の問題に対応するためには、プロセス終了・再起動の手法しか対応が取れない為 そう考えているのです。幸い Java言語は ソケットが非常に扱いやすいので、プロセス間通信が簡便に記述でき プロセス分割は行いやすいと思います。
おわりに

Javaにおけるデータベース周りの事象について ざっくりと見てきましたが どうだったでしょうか? いろいろ問題点を見つけ出して指摘したので、どうもネガティブなイメージを植え付けまくってしまったかもしれません。しかし一方 上記のような点に注意して また回避策を取りながら利用すれば、JDBC環境は 快適で またすぐ利用できるレベルに到達しつつあるのだとも私は考えています。本稿のような記事が増えてくるにつれ、そのような状況は 更に改善されて行くことを期待しています。

なお 本稿は 執筆時点では あまり他に同様の資料を見かけることが出来ませんでした。このため、間違いも多く含まれているかと思います。本稿は みなさんの考えるきっかけとして用いていただければうれしいです。まずはみなさんが 自らの手で これらデータベース周りの事象を試されることを最も期待します。
本稿が Java および JDBC の 更なる発展に寄与することを祈って。

参考文献
サポートページ
更新履歴

midori.iga@nifty.ne.jp
$Date: 2008/05/24 06:22:36 $