Specification of QDBM for Java

Copyright (C) 2000-2003 Mikio Hirabayashi
Last Update: Fri, 04 Apr 2003 00:48:37 +0900
[API][English] [Home]

Table of Contents

  1. 概要
  2. インストール
  3. 環境設定
  4. サンプルコード
  5. バグ

概要

QDBMにはJava言語用のAPIがある。QDBMの基本APIと拡張APIの関数群をJavaのクラス機構を用いてカプセル化し、かつスレッドセーフにしたものである。C言語のAPIをJava Native Interfaceを介して呼び出すように実装されている。

基本APIはファイルを用いてデータベースを実現する。クラス `Depot' のコンストラクタによってデータベースファイルが開かれる。データベースを閉じるにはメソッド `close' を呼ぶ。ファイナライザでもデータベースを閉じようとするが、それに頼ってはならない。メソッド `put' はレコードを追加するために用いる。メソッド `out' はレコードを削除するために用いる。メソッド `get' はレコードを検索するために用いる。その他にも、C言語の基本APIとほぼ同じ操作を利用することができる。各メソッドはエラー時にクラス `DepotException' のインスタンスを投げる。

拡張APIはディレクトリと複数のファイルを用いてデータベースを実現する。クラス `Curia' のコンストラクタによってデータベースファイルが開かれる。データベースを閉じるにはメソッド `close' を呼ぶ。ファイナライザでもデータベースを閉じようとするが、それに頼ってはならない。メソッド `put' はレコードを追加するために用いる。メソッド `out' はレコードを削除するために用いる。メソッド `get' はレコードを検索するために用いる。その他にも、C言語の拡張APIとほぼ同じ操作を利用することができる。各メソッドはエラー時にクラス `CuriaException' のインスタンスを投げる。

クラス `Depot' とクラス `Curia' はともにインタフェース `ADBM' を実装する。このインタフェースはUNIX標準のDBMと同様の機能を持つデータベースマネージャを抽象化したものである。各メソッドはエラー時にクラス `DBMException' のインスタンスを投げる。3つのAPIから適切なものを選択する際には、実行効率を重視するなら `Depot' を、スケーラビリティを重視するなら `Curia' を、エレガンスと保守性を重視するなら `ADBM' を選ぶべきであろう。

APIの詳細に関しては、サブディレクトリ `japidoc' の文書と各ヘッダファイルを参照すること。


インストール

インストール作業は、サブディレクトリ `java' をカレントディレクトリにして行う。

ビルド環境を設定する。

./configure

プログラムをビルドする。

make

プログラムの自己診断テストを行う。

make check

プログラムをインストールする。作業は `root' ユーザで行う。

make install

一連の作業が終ると、ネイティブライブラリ `libjqdbm.so.0.0' 等とJARファイル `qdbm.jar' が `/usr/local/lib' にインストールされる。

アンインストールするには、`./configure' をした後の状態で以下のコマンドを実行する。作業は `root' ユーザで行う。

make uninstall

Windows(Cygwin)にインストールする場合、以下の手順に従う。

ビルド環境を設定する。

./configure

プログラムをビルドする。

make win

プログラムの自己診断テストを行う。

make check

プログラムをインストールする。なお、アンインストールする場合は `make uninstall-win' とする。

make install-win

Windowsでは、インポートライブラリ `libjqdbm.dll.a' が生成され、さらにダイナミックリンクライブラリ `jqdbm.dll' が生成される。`jqdbm.dll' は `C:\WINNT\SYSTEM32' のようなシステムディレクトリにインストールされる。


環境設定

QDBMを利用したJavaプログラムをビルドしたり、それを実行するには、環境変数を設定しておく必要がある。

クラスパスを設定する。環境変数 `CLASSPATH' の値がJARファイルのフルパスを含むようにする。

CLASSPATH=$CLASSPATH:/usr/local/lib/qdbm.jar
export CLASSPATH

ライブラリパスを設定する。環境変数 `LD_LIBRARY_PATH' の値がライブラリのあるディレクトリを含むようにする。

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
export LD_LIBRARY_PATH

サンプルコード

名前と対応させて電話番号を格納し、それを検索するアプリケーションのサンプルコードを以下に示す。

import qdbm.*;

public class Sample5 {

  static String NAME = "mikio";
  static String NUMBER = "000-1234-5678";
  static String DBNAME = "book";

  public static void main(String[] args){
    Depot depot = null;
    try {

      // データベースを開く
      depot = new Depot(DBNAME, Depot.OWRITER | Depot.OCREAT, -1);

      // レコードを格納する
      depot.put(NAME.getBytes(), NUMBER.getBytes());

      // レコードを検索する
      byte[] res = depot.get(NAME.getBytes());
      System.out.println("Name: " + NAME);
      System.out.println("Number: " + new String(res));

    } catch(DepotException e){
      e.printStackTrace();
    } finally {

      // データベースを閉じる
      if(depot != null){
        try {
          depot.close();
        } catch(DepotException e){
          e.printStackTrace();
        }
      }

    }
  }

}

上記の例を `ADBM' クラスを用いて書き直した例を以下に示す。

import qdbm.*;

public class Sample6 {

  static String NAME = "mikio";
  static String NUMBER = "000-1234-5678";
  static String DBNAME = "book";

  public static void main(String[] args){
    ADBM dbm = null;
    try {

      // データベースを開く
      dbm = new Depot(DBNAME, Depot.OWRITER | Depot.OCREAT, -1);

      // レコードを格納する
      dbm.storeobj(NAME, NUMBER, true);

      // レコードを検索する
      Object res = dbm.fetchobj(NAME);
      System.out.println("Name: " + NAME);
      System.out.println("Number: " + res);

    } catch(DBMException e){
      e.printStackTrace();
    } finally {

      // データベースを閉じる
      if(dbm != null){
        try {
          dbm.close();
        } catch(DBMException e){
          e.printStackTrace();
        }
      }

    }
  }

}

Java用APIを利用したプログラムをビルドするには、クラスパスを適切に設定した上で、`javac' を実行する。例えば、`Sample.java' から `Sample.class' を作るには、以下のようにビルドを行う。

javac Sample.java

バグ

ひとつのプロセスで複数のデータベースファイルを同時に利用することは可能であるが、同じデータベースファイルの複数のハンドルを利用してはならない。ひとつのデータベースを複数のスレッドで利用する場合には、メインスレッドで生成したハンドルを他のスレッドに渡せばよい。

オブジェクトを直列化してデータベースに格納するメソッドは便利であるが、オブジェクトの直列化は時間的および空間的に効率がよくない。明示的にバイト配列に変換できるならば、なるべくバイト配列のAPIを用いた方がよい。