db4o その3(オープン/クローズとサーバモード)

db4oにおけるDBのオープンとクローズだが、前回のエントリで書いたようなローカルにあるデータベースを単純に開く方法について説明した。

String dbPath = "stats.db";
ObjectContainer db = Db4o.openFile(dbPath);
try {
    //データベースに対する処理
} finally {
    db.close();
}

当然だがこの方法では開かれたデータベース・ファイルを排他的に利用することになるので、例えば複数のスレッドからデータベースをオープンしようとすると例外がスローされる。

Exception in thread "Thread-0" com.db4o.ext.DatabaseFileLockedException: Database locked: 'stats.db'

これではC/S(Client/Server)型などの二層のシステムやマルチタスクの処理に対応できないので、db4oはデータベースをクライアント/サーバモードでオープンし、複数のクライアントが同時にデータベースに接続するモードが用意されている。(この辺は同じく組込み用途を想定しているHSQLDBやH2DBとよく似ている)

  • データベースをサーバモードでオープンする

サーバモードでオープンするのは簡単だ。以下のようにスタティックなメソッドを使用するだけである。

String dbPath = "stats.db";
ObjectServer os = Db4o.openServer(dbPath, 0);

第一パラメタはopenFileメソッドと同じであり、第二パラメタはサーバがリスンするポートを指定する。ここでサーバはjava.io.ServerSocketを生成してオープンするのだが、上記のようにポートに0を指定すると"EmbeddedServer"モードとなりサーバモードであってもソケットは生成せず、リモートプロセスから接続することもできない。
リモートから接続する本当の意味でのサーバモードの場合は0以外のポートを指定すると共に、接続する際に許可するユーザ名とパスワードを指定する。

String dbPath = "stats.db";
ObjectServer os = Db4o.openServer(dbPath, 0xdb40);
os.grantAccess("db4o", "db4o");

openServerメソッドが返すObjectServerインタフェースはサーバ、もしくは"EmbeddedServer"モードでオープンされたサーバに接続するクライアントが使用する、必要最小限の操作が定義されている。

interface ObjectServer {
    boolean close();
    ExtObjectServer ext();
    void grantAccess(String userName, String password);
    ObjectContainer openClient();
    ObjectContainer openClient(Configuration config);
}
  • データベースサーバに接続する

サーバに接続するにはサーバがどのようなモードで開かれているかによって変わる。
1. ローカルクライアントモード
同一のコンテキスト上で接続するモードであり、上記ObjectServerインタフェースのopenClientメソッドを使用する。

String dbPath = "stats.db";
ObjectServer os = Db4o.openServer(dbPath, 0);
ObjectContainer oc = os.openClient();

2. リモートクライアントモード
リモートプロセスでオープンされているdb4oサーバに接続するためにはDb4oクラスのopenClientメソッドを使用する。

ObjectContainer oc = Db4o.openClient("localhost", 0xdb40, "db4o", "db4o");

ObjectServer#openClient()、Db4o.openClient(String, int, String, String)の両メソッドはオープンが成功するとObjectContainerインタフェースを返すが、これは「・データベースサーバに接続する」で説明したのと同様に前者は擬似ソケットによるインプロセス通信を行い、後者はjava.io.Socketクラスを使用してdb4oのサーバとソケット通信を行うことになる。
これら両メソッドでdb4oサーバに接続する場合、送受信されるオブジェクトは全てシリアライズ/デシリアライズ処理を通して実体化される。また、サーバから取得したObjectContainerインタフェースが参照しているオブジェクトはWeakReferenceとしてキャッシュされることを理解しておく必要があるだろう。(このことはdb4oのクエリ結果に対して非常に重要な意味を持つことになる)