seraphyの日記

日記というよりは過去を振り返るときのための単なる備忘録

Apache Derbyで新規データベースにテーブルを自動構築する簡単な方法

新規データベース作成後の処理

Apache Derbyを埋め込みモードで使う場合、指定したパス上にデータベースが存在しない場合、接続URLのオプションとして、自動的に作成するように指示することができる。


たとえば、以下のような接続URLである。

DriverManager.getConnection("jdbc:derby:memory:myDb;create=true").close();

上記指定のインメモリデータベースは、前の状態など存在しないので、当然、新規作成のオプションは必須となろう。


ただし、この方法では、データベースは自動的に作成されるが、アプリケーションを動作させるに必要なテーブルや初期マスタデータなどが存在しない。

これらは、アプリケーションが自分で作成しなければならない。


これを簡単に実現するには、以下のような手順となる。

  1. 接続URLのオプションとして「create=true」を指定し、データベースが未存在ならば自動作成するように指示する。
  2. コネクションを取得したらDatabaseMetaDataで、定義されているテーブルを取得する
  3. テーブルが定義されていなければ、対話ツールijのクラスのPublic API「runScript」を呼出し、DDLを記述したスクリプトを読み込ませる。
    1. runScriptメソッドは失敗したエラー数を戻り値とし、ijの場合と同じようにテキスト形式のログを出力とする.
    2. スクリプトのエラー個所はわからないので、runScriptを、いくつかに分割すると良いかもしれない。(たとえば、dropとcreateとか。)
  4. 用意するDDLスクリプト
    1. 対話ツールijでデバッグしながら手作業で作成したものでも良いし
    2. Apache Derbyの付属ツールdblookを使えば、既存のデータベースのテーブル定義等一式をスクリプトとして出力できるので、これを使ってもよい。

テータベース上の定義済みテーブル一覧の取得方法

// データベースのAPPスキーマに登録されているテーブル一覧
HashSet<String> existTableName = new HashSet<String>();
DatabaseMetaData dbMeta = conn.getMetaData();
ResultSet rs = dbMeta.getTables(null,"APP","%",null); // 大文字
try {
    while (rs.next()) {
        String tableName = rs.getString("TABLE_NAME");
        existTableName.add(tableName);
    }

} finally {
    rs.close();
}

Apache Derbyを組込みモードでつかう場合、スキーマは「APP」となる。


システム定義のテーブルは列挙する必要ないので、APPスキーマ限定でテーブル名を取り出しておく。

対話ツールijのクラスの利用

クラスパスの指定

以下の3つのjarをクラスパスに通す必要がある。

  • derby.jar 本体
  • derbytools.jar 対話ツールijが含まれる
  • derbyLocale_ja_JP.jar 日本語リソース
runScriptの実行方法
InputStream inp = new BufferedInputStream(
        new FileInputStream(ddlScript));
try {
    // ijのrunScriptを使用してスクリプトを一括ロードする.
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    int ret = ij.runScript(conn, inp, "MS932", bos, "UTF-8");

    // 結果のログへの書き込み
    String msg = new String(bos.toByteArray(), "UTF-8");
    log.info("load script(numOfFailed=" + ret + ") output=" + msg);

} finally {
    inp.close();
}

※ ijという小文字のクラス名なので注意。(runScriptはstaticメソッドである。)


ij上でrunコマンドでスクリプトを流した場合と同様に、スクリプトの途中でエラーが発生してもスクリプトは最後まで流れる。


また、戻り値として、エラーの発生回数が返される。
ただし、不明なエラーが発生した場合は-1が返される。

よって、runScriptの戻り値が0以外ならば何らかの問題が発生していることを示す。


エラーの発生回数しか把握できないので、なにがエラーになったかはわからない。


しかし、runScriptコマンドを何回かに分けて呼び出すことで、エラーの発生場所と、それによる対処を決めることはできるかもしれない。(たとえば、drop/createなら、dropでエラーになっても無視して、createが全て成功すれば良い。)

そもそもデータベースをコピーしてしまう方法もある

apache derbyの接続URLのオプションには「createFrom=」という指定もあり、既存のデータベースをもとに新規にデータベースを作成する機能もある。(restoreFrom=という指定もある。)


ただし、こちらはデータベースがすでに存在する場合はエラーとなるため、指定したディレクトリ上にデータベースが存在しない場合に、オプションをつけて呼び出す、といった手順が必要となるだろう。
(restoreFrom=を使えば、常にデータベースを上書きすることになる。)



以上、メモ終了