新トップページへ | Tip

Windows上でjavaDBをとりあえず使ってみる

LstUpdate : 08/05/10

 javaDB使い方について、メモしてみます。
なんというか、仕事でこれを使ってるわけでも、これ用の専門書籍とかを持ってるわけでもなしなので、ほんとーに、触ってみた感じで、思いついたことの感想や、めも程度のレベルです。まちがってるところ・不明な点がいっぱいあります。注意してください。

 組み込み用DBとしても、複数人が接続して使うDBとしても、両方使うことができる便利そーなDBです。なおかつライセンスがかなりゆるい様子です(ちゃんと調べてませんが)。

 で、私の目的は、組み込み用DBとしてjavaDBは使えんかなぁ〜と、思いついて、調べてみました。一応、組み込み・ネットワーク両方の情報を調べてみました。

 JavaDBそのものは、JDK6などをインストールした際、一緒にインストールされます。なので、特別、インストールする必要はありません。
私の環境では、JDKがインストール場所は「 C:\Program Files\Java\jdk1.6.0_03 」です。
そして、javaDBは「 C:\Program Files\Sun\JavaDB 」にインストールされていました。
javaDBにおいて、コマンド・スクリプトは「 C:\Program Files\Sun\JavaDB\bin 」の中にあります(が、JDKのバージョンによって違うような感じ)。

マニュアルの類も、一緒にインストールされる様子です(英語ですが)
しかし、ネット上に、いちおー、日本語になったものが存在する様子です(たまたまみつけた

http://db.apache.org/derby/docs/dev/ja_JP/getstart/
http://db.apache.org/derby/docs/dev/ja_JP/ref/

 インストールディレクトリの中を見てみると、シェルスクリプトとバッチファイルがあります。
今回、私はWindows上で操作をしますので、このバッチファイルを使用していきます。
 また、基本的なjavaDBをjavaから使う場合の、サンプルコードが、javaDBのインストールディレクトリ以下の、demoディレクトリにあります。

ちなみに、javaDBそのものが、どういう経緯のものなのかは、てきとーにググルとでてくるハズです。

使えるかどーか試してみる
パスの設定
ijでjavaDBに接続(ネットワーク)
javaのプログラムから接続してみる(ネットワーク)
組込みDBとして使う(組込み)
いろいろ
binディレクトリの中にあるファイルの説明
開発する際のクラスパスの設定とか
DBのデータファイルの保存パスを指定する
DBのポート番号やホストアドレスを指定したい(ネットワーク)
DBアクセスにユーザの識別・認証を追加(ネットワーク)

パスの設定

 JDKをインストールし、JAVA_HOMEの設定やjavacなどをコマンドラインからjavacなどのコマンドを使うために、binディレクトリのパスを通す・・・、とそれとプラスアルファで、以下の作業を行います。

 インストールディレクトリがJDKとは別個なので、そのjavaDBがインストールされたディレクトリへのパスを通す作業を行います。

(1)windowsの環境変数に

DERBY_HOME → C:\Program Files\Sun\JavaDB

を設定します。

(2)さらにいうと、pathに「 javaDB\bin 」のところも通しておく(たぶん、これは必須ではないです)

ちなみに、javaDBのjarファイルはlibディレクトリの中にあります(私の環境では「 C:\Program Files\Sun\JavaDB\lib 」)。これらは、開発・実行する際に、必要なので、メモっておきます。

で、コマンドプロンプトから、「sysinfo」と打ち込み(環境変数にjavaDBのbinディレクトリにパスを通している場合)いろいろと情報が表示されたならば、OKです。


※ アフォなことに、c:\Programファイルは実行ファイルではない、うんぬんとエラーメッセージがでてくる場合があります。
そう・・・、JDKのデフォルトで指定しているインストールパスは「c:\Program Files\」の中なのです(で、私はデフォルトの場所にインストールしてたw)。
このスペース文字が曲者で・・・。

各種バッチファイルの内で

CALL %~dp0derby_common.bat %*

という記述があります。
正直な話、私はWindowsのバッチファイルの文法は全然知らんのですが、まぁ、こいつが原因の様子です(ちなみに、私の環境はWindowsVista)。というわけで、私は、以下のように修正し、それとなく動作するようになりました。

CALL derby_common.bat

まぁ・・・、たぶん、derby_common.batが呼べれば問題なかろーかと・・・。

※ちなみに・・・・(frameworksディレクトリの話)
frameworksというディレクトリがありますが、マニュアルには、「このリリースでは後方互換性のために提供されています」と書かれています。下位互換のために、存在するらしい。なので、私はこのディレクトリの中にあるファイルは気にしないことにしました(マニュアルが対象にしているバージョンと、私が使っているjavaDBのバージョンが異なるかどーかすら調べていませんが、まぁ、そんなもんだろー的な解釈を、個人的にしてます)。

ijでDBに接続 

 ijとは、PostgreSQLでいうpsqlのよーなものです(DB2でいうCLP。OracleでいうSQL*PLUS)。
で、こいつで、DBと接続をしてみます。

※javaDB\binディレクトリへ、パスが通っている状態を前提にしています。

(1)stopNetworkServer.batを実行
 javaDBのサーバを起動し、接続を待ち受け状態にします。別に、コマンドプロンプトだろうが、エクスプローラからこのバッチファイルをダブルクリックだろうが、どちらでもいいです。

サーバが起動すると、以下のようなメッセージが表示されます。

Apache Derby Network Server - 2008-05-11 09:21:07.845 GMT に 10.2.2.0 - (485682)
 が開始され、ポート 1527 で接続を受け入れる準備ができました。

(2)コマンドプロンプトからijを起動
 ijを使い、(1)で起動したdbへ接続を行います。

C:\Users\admin>ij
ij バージョン 10.2
ij> connect 'jdbc:derby://localhost/testDB;create=true';
ij> show tables
;
TABLE_SCHEM         |TABLE_NAME                    |REMARKS
------------------------------------------------------------------------
SYS                 |SYSALIASES                    |
SYS                 |SYSCHECKS                     |
SYS                 |SYSCOLPERMS                   |
SYS                 |SYSCOLUMNS                    |
SYS                 |SYSCONGLOMERATES              |
SYS                 |SYSCONSTRAINTS                |
SYS                 |SYSDEPENDS                    |
SYS                 |SYSFILES                      |
SYS                 |SYSFOREIGNKEYS                |
SYS                 |SYSKEYS                       |
SYS                 |SYSROUTINEPERMS               |
SYS                 |SYSSCHEMAS                    |
SYS                 |SYSSTATEMENTS                 |
SYS                 |SYSSTATISTICS                 |
SYS                 |SYSTABLEPERMS                 |
SYS                 |SYSTABLES                     |
SYS                 |SYSTRIGGERS                   |
SYS                 |SYSVIEWS                      |
SYSIBM              |SYSDUMMY1                     |

19 行が選択されました
ij>

以下のオプションをつけることで、指定したデータベースが存在しない場合、データベースを作成し、接続を行います。

create=true

ちなみに、最後の「;」(セミコロン)をつけないと、コマンドは実行されません。

(3)ためしにテーブルを作成し、データを挿入、表示を行ってみる。

ij> CREATE TABLE MessageTBL
(
        id      integer primary key,
        message varchar(100),
        flg     integer
);
0 行が挿入/更新/削除されました
ij> INSERT INTO MessageTBL(id,message,flg) VALUES( 1, 'てすとだよんーんw', 0 );

1 行が挿入/更新/削除されました
ij> SELECT * FROM MessageTBL;
ID         |MESSAGE
                                |FLG
--------------------------------------------------------------------------------
--------------------------------------------
1          |てすとだよんーんw
                                         |0

1 行が選択されました
ij>

 と、まぁ、こんな感じです。コンソール上で、トランザクションのスタートだとかコミットのコマンドだとか、あるにはあるんでしょーが、面倒なのでこのへんで。
・・・これってオートコミットなはず・・・。たぶん。

(4)終了処理

 ijを終了する。

ij> quit;
C:\Users\admin>

quitコマンドで終了します。

次に、DBを停止します。
binディレクトリ内の、「 stopNetworkServer.bat 」をコンソールから実行するなり、エクスプローラからダブルクリックすると、startNetworkServerで起動したDBサーバが停止します。

たぶん、これで、OK・・・なはず・・・^^;

javaのプログラムから接続してみる

 とりあえず、サーバを起動し、JavaのプログラムからSQLで問い合わせを行ってみます。

用意されているバッチをみると、サーバの起動・停止は「NetworkServerControl.bat」に、引数をつけてやる感じっぽいですが、例のごとく、うまく動かないので(直す気力も沸かない)、startNetworkServer/stopNetworkServerを使います。

 startNetworkServerを使い、サーバを起動します。デフォルトでは待ち受けポートは1527になるかと思います。
この状態で以下のプログラムを実行します。

javaDBTest1.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;


public class javaDBTest1 {
        
        /** データベース接続用 */
        Connection con;
        
        /** メイン */
        public static void main(String[] args) {
                System.out.println("javaDB test program...");
                javaDBTest1 obj = new javaDBTest1();
                
                try {
                        //DBに接続
                        obj.connectDB();
                        //データを表示する
                        obj.showTable();
                }catch(SQLException e) {
                        e.printStackTrace();
                }catch(ClassNotFoundException e) {
                        e.printStackTrace();
                }
                finally {
                        //DBから接続解除
                        obj.disconnectDB();
                }
                
                System.out.println("finish...");
        }
        
        /** データベースに接続 */
        private void connectDB() throws SQLException,ClassNotFoundException {
                Class.forName("org.apache.derby.jdbc.ClientDriver");
                System.out.println("ドライバ読み込みOK");
                
                Properties prop = new Properties();
                prop.put("create" ,"true");             //指定したデータベースが存在しない場合、作成する
                //ユーザIDとパスワードは設定が施していある場合、指定する。
                //prop.put("user" ,"admin");            //DBに接続する際のユーザ名を指定
                //prop.put("password" ,"admin");        //パスワードを指定
                
                con = DriverManager.getConnection("jdbc:derby://localhost:1527/testDB", prop);
                System.out.println("接続OK");
        }
        
        /** データを表示する */
        private void showTable() throws SQLException {
                Statement st = con.createStatement();
                //DBの新規作成時はテーブルがないので作成し、データの挿入を行う。
                try {
                        st.executeUpdate("CREATE TABLE MessageTBL(id integer,message varchar(100))");
                        st.executeUpdate("INSERT INTO MessageTBL VALUES(1 ,'てすとですーーーーーーーww')");
                } catch(SQLException e){}
                
                //データを取得し、表示する。
                ResultSet res = st.executeQuery("SELECT * FROM MessageTBL");
                while(res.next()) {
                        System.out.println("id : "+res.getInt("id")+" / Message : "+res.getString("message"));
                }
                
                //それとなくリソース開放。
                try{    res.close();    }catch(SQLException e){}
                try{    st.close();     }catch(SQLException e){}
        }
        
        /** データベースから接続を解除 */
        private void disconnectDB(){
                if( con != null ) {
                        try {   con.close();    }
                        catch(SQLException e){  e.printStackTrace();    }
                        con = null;
                }
                System.out.println("開放処理終了");
        }

}

実行する際、javaDBのlibディレクトリにある、以下のjarをクラスパスに指定し実行します(Eclipseなんかだと、「javaのビルド・パス」→「外部jarの追加」などで、指定します)。

derbyclient.jar
derbytools.jar

まぁ、内容はくだらないですが。
実行すると、以下のような実行結果を得られるはずです。

javaDB test program...
ドライバ読み込みOK
接続OK
id : 1 / Message : てすとだよんーんw
開放処理終了
finish...

とりあえず、一応、使えることが確認できたかと思います。

DBを終了させるため「stopNetworkServer.bat」を実行すればOKです。

組込みDBとして使う

 組込みDBとしてjavaDBを使用します。ファイルI/Oメソッドを使う代わりにSQLでデータの参照・保存ができるーって感じです。

さてはて、どのよーにすればいいのか、悩んでいたところ、ここ( http://db.apache.org/derby/docs/dev/ja_JP/getstart/cgsquck35643.html)には、

「同一のJVM内で、Derbyインスタンスを起動するとき、それは組み込み環境での実行ということになります」

だなんて、書いてあるじゃありませんか。
で、組み込み用ドライバをロードすると、Derbyが自動的に起動するらしい。

 というわけで、やってみました。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;


public class javaDBTest2 {
        
        /** データベース接続用 */
        Connection con;
        
        /** メイン */
        public static void main(String[] args) {
                System.out.println("javaDB test program...");
                javaDBTest2 obj = new javaDBTest2();
                
                try {
                        //DBに接続
                        obj.connectDB();
                        //データを表示する
                        obj.showTable();
                }catch(SQLException e) {
                        e.printStackTrace();
                }catch(ClassNotFoundException e) {
                        e.printStackTrace();
                }
                finally {
                        //DBから接続解除
                        obj.disconnectDB();
                }
                
                System.out.println("finish...");
        }
        
        /** データベースに接続 */
        private void connectDB() throws SQLException,ClassNotFoundException {
                Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
                System.out.println("ドライバ読み込みOK");
                
                Properties prop = new Properties();
                prop.put("create" ,"true");             //指定したデータベースが存在しない場合、作成する
                //ユーザIDとパスワードは設定が施していある場合、指定する。
                //prop.put("user" ,"admin");            //DBに接続する際のユーザ名を指定
                //prop.put("password" ,"admin");        //パスワードを指定
                
                con = DriverManager.getConnection("jdbc:derby:testDB1", prop);
                System.out.println("接続OK");
        }
        
        /** データを表示する */
        private void showTable() throws SQLException {
                Statement st = con.createStatement();
                //DBの新規作成時はテーブルがないので作成し、データの挿入を行う。
                try {
                        st.executeUpdate("CREATE TABLE MessageTBL(id integer,message varchar(100))");
                        st.executeUpdate("INSERT INTO MessageTBL VALUES(1 ,'てすとですーーーーーーーww')");
                } catch(SQLException e){}
                
                //データを取得し、表示する。
                ResultSet res = st.executeQuery("SELECT * FROM MessageTBL");
                while(res.next()) {
                        System.out.println("id : "+res.getInt("id")+" / Message : "+res.getString("message"));
                }
                
                //それとなくリソース開放。
                try{    res.close();    }catch(SQLException e){}
                try{    st.close();     }catch(SQLException e){}
        }
        
        /** データベースから接続を解除 */
        private void disconnectDB(){
                if( con != null ) {
                        //普通の接続のクローズ処理
                        try {   con.close();    }
                        catch(SQLException e){  e.printStackTrace();    }
                        con = null;
                        
                        //DB全体を停止する処理
                        try {
                                DriverManager.getConnection("jdbc:derby:;shutdown=true");
                        } catch(SQLException e) {
                                //しっかりと終了できた場合、XJ015という例外が発せられるのでそれを確認する。
                                if( e.getSQLState().equals("XJ015") ) {
                                        System.out.println("DBのシャットダウンが完了しました。");
                                } else {
                                        //XJ015以外は普通の例外なので、とりあえずprintStacTraceする。
                                        e.printStackTrace();
                                }
                        }
                }
                System.out.println("開放処理終了");
        }

}

実行する際、javaDBのlibディレクトリにある、以下のjarファイルをクラスパスに追加します(Eclipseなんかだと、「javaのビルド・パス」→「外部jarの追加」などで、指定します)。

derby.jar
derbytools.jar

実行すると、以下のような出力が得られるはずです。

javaDB test program...
ドライバ読み込みOK
接続OK
id : 1 / Message : てすとですーーーーーーーww
DBのシャットダウンが完了しました。
開放処理終了
finish...

 ネットワークのクライアント用のプログラムとの違う点は、二つあります。

(1)読み込ませるドライバが違う
(2)終了処理が1ステップ増える。

 (1)については、まあ、普通です。
(2)については、ソースにあるように、getConnectionで、shutdown=trueという文字列を渡してやり、DBを終了します。なおかつ、不思議なことに、正常に終了したならば、例外が飛んできます。そして、こいつが、XJ015という文字列ならば、ちゃんと正常に終了したことが確認できるらしいです。

それと、データベースのファイルが作成される場所ですが、どーやら、カレントディレクトリの様子です。変更する方法は調べ中・・・。

binディレクトリの中にあるファイルの説明

ij ij(PostgreSQLでいうところのpsql。DB2でいうところのCLP)を起動する。これで、コンソールからDBをうだうだといじれる。
startNetworkServer 複数人で使うためのDB起動する。
stopNetworkServer startNetworkServerで起動したDBサーバを停止する
sysinfo 現在の状況が表示される(jvmのバージョンや各種jarファイルのパスなど)。ただの情報が表示されるだけの確認用かと。
setEmbeddedCP 環境変数CLASSPATHに、組み込み用にjarファイルをセットする。
setNetworkClientCP 環境変数CLASSPATHに、ネットワーク環境用のクライアント用にjarファイルをセットする。
startNetworkServer 環境変数CLASSPATHに、ネットワーク環境用のサーバー用にjarファイルをセットする。
derby_common ほかのスクリプトで、使用される変数をここで、setしている様子です(startNetworkServerなど、最初に、このバッチファイルを呼び出している。)
NetworkServerControl 引数をつけて、いろいろとDBへ命令を出す。サーバの起動など、たぶん、こちらを基本的に使う。startNetworkServer/stopNetworkServerと少々内容が違うだけで、やってることはほぼ一緒ですが・・・。(私の環境ではちゃんと動かないので、startNetworkServer/stopNetworkServerを少しいじって、使ってます)。
dblook javaDB\binの中にあるファイルは組み込み用のファイルなんだそーです。
で、それをネットワーク用に使うためには、これを使い、
   dblook -d 'jdbc:derby://サーバアドレス/データベース名前;user=ユーザ名'
のような感じのコマンドを打たねばならないらしいです。

開発する際のクラスパスの設定とか

 ネットワーク経由で、クライアントとして動作させる場合、サーバーとして、動作させる場合、組み込み用として動作させる場合と、指定するjarファイルが異なります。以下のものを指定すればいいらしいよ?(マニュアルを読んだだけで、サーバ用についてはやってみたことないです。

組込み用
derby.jar
derbytools.jar
サーバ用
derby.jar
derbynet.jar
サーバのクライアント用
derbyclient.jar
derbytools.jar

DBのデータファイルの保存パスを指定する

 デフォルトでは、DBのファイルは明後日のところに保存されます。ほんと、びっくりするようなところに保存してくれるので、保存場所をこちらが指定したほうがいいかと思います。

とりあえず、方法として「startNetworkServer.bat」の中でorg.apache.derby.drda.NetworkServerControlを実行している部分があるのですが、そこで、「このパスを使ってね〜」と指定してあげます。
方法としては、以下のように、DERBY_OPTSに値を事前に指定して、NetworkServerControlが実行されるとき、うまくオプションがわたるようにします。
私は、

私がすこしいじったstartNetworkServer.batファイルの内容
@echo off

@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at

@REM http://www.apache.org/licenses/LICENSE-2.0

@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.

CALL derby_common.bat


@REM ADD 0:24 2008/05/11 データの格納場所を指定するよう変更
SET DERBY_OPTS=-Dderby.system.home=c:\db
 ←この部分を追加

if "%_USE_CLASSPATH%"=="no" goto runNoClasspath
if not "%CLASSPATH%"=="" goto runWithClasspath


:runNoClasspath
"%_JAVACMD%" %DERBY_OPTS% -classpath "%LOCALCLASSPATH%" org.apache.derby.drda.NetworkServerControl start
goto end

:runWithClasspath
"%_JAVACMD%" %DERBY_OPTS% -classpath "%CLASSPATH%;%LOCALCLASSPATH%" org.apache.derby.drda.NetworkServerControl start
goto end

:end
set _JAVACMD=
set DERBY_CMD_LINE_ARGS=

.NetworkServerControl start goto end :end set _JAVACMD= set DERBY_CMD_LINE_ARGS=

これで、たぶん、うまく行く・・・ハズですw
c:\dbのディレクトリのなかに、DBのデータが作成されるはずです(ただ、パスを変更したため、データベースの内容は空っぽです)。

DBのポート番号やホストアドレスを指定したい

 デフォルトではlocalhostでポート番号が1527になる様子です。
もちろん、普通に動かすなら、変更したいと思うハズです。

 org.apache.derby.drda.NetworkServerControlを実行する際に、オプションとして指定してやれば、指定したホストアドレス・ポートで動くようになるみたいです。

startNetworkServer.bat と stopNetworkServer.batに手を加えます。

startNetworkServer.bat の変更点
"%_JAVACMD%" %DERBY_OPTS% -classpath "%CLASSPATH%;%LOCALCLASSPATH%" org.apache.derby.drda.NetworkServerControl start

"%_JAVACMD%" %DERBY_OPTS% -classpath "%CLASSPATH%;%LOCALCLASSPATH%" org.apache.derby.drda.NetworkServerControl start -h localhost -p 50000

という具合に、-hと-pをつけて、ホストアドレス、ポート番号を指定してやればOKらしいです。
例では、私の動かしているマシンはただのクライアントマシンなので(サーバとして動かす気が無い)、localhostと指定しています。

stopNetworkServer.bat の変更点
"%_JAVACMD%" %DERBY_OPTS% -classpath "%CLASSPATH%;%LOCALCLASSPATH%" org.apache.derby.drda.NetworkServerControl shutdown

"%_JAVACMD%" %DERBY_OPTS% -classpath "%CLASSPATH%;%LOCALCLASSPATH%" org.apache.derby.drda.NetworkServerControl shutdown -h localhost -p 50000

そして、startNetworkServer.bat も同じように変更します。そうしないと、どれを止めていいのかわからなくなってしまいますので。

これで、再びサーバを起動させれば、変更が反映されているはずです。

DBアクセスにユーザの識別・認証を追加

 デフォルトの状態で、ijを使ってデータベースにアクセスする際、IDやパスワードを入力するように、促されません。
なぜなら、設定をしてないからです。
識別・認証なしに、アクセスできます。
 そのため、ユーザ識別・認証を加えるために、設定を行います。

 データベースの保管ディレクトリの中に「derby.propeties」というファイルを以下のような内容でファイルを作成します。

derby.properties
#
#識別・認証を有効にする
#
derby.connection.requireAuthentication=true
derby.authentication.provider=BUILTIN

#
#ユーザをここで追加・削除を行う
#
#文法:
#  derby.user.ユーザ名前=パスワード
#例:
#  derby.user.user1=passwd
#  この場合IDが user1 となり、パスワードがpasswdになる。
#
derby.user.admin=admin

この状態では、ユーザID「admin」、パスワード「admin」というユーザがいる状態です。
ユーザID「admin」、パスワード「admin」を指定しないと、このデータベースに接続できない状態になっているはずです。

ユーザが追加したい場合は下の行に、どんどん同じフォーマット(「derby.user.ユーザ名前=パスワード」の形)で追加していけばいいだけです。