S-JIS[2009-02-22/2015-03-07] 変更履歴

JavaDBメモ

JavaDBは、JDK1.6をインストールするだけで使えるRDB
実体は、Apacheプロジェクトで作られた「Apache Derby」というDBだそうだ。


ライブラリーの準備

JavaDBを使うためには、JavaDB用のJDBCドライバーの入っているライブラリー(jarファイル)が必要。

クラスパスにderby.jarを追加するだけでよい。
Eclipseでビルドパスにjarファイルを追加する方法

ライブラリーは以下の場所にある。
(JDK1.6をインストールしておく(インストールの際にJavaDBを対象に含んでおく)と、以下の場所にjarファイルが存在しているはず。JREのみのインストールではダメ)

■JDK1.6.0(_02より前)
●組み込み環境用
C:\Program Files\Java\jdk1.6.0\db\lib\derby.jar
●クライアント/サーバー環境用
C:\Program Files\Java\jdk1.6.0\db\lib\derbyclient.jar
■JDK1.6.0_02以降
●組み込み環境用
C:\Program Files\Sun\JavaDB\lib\derby.jar
●クライアント/サーバー環境用
C:\Program Files\Sun\JavaDB\lib\derbyclient.jar
■JDK1.8 [2015-03-07]
●組み込み環境用
C:\Program Files\Java\jdk1.8.0_25\db\lib\derby.jar
●クライアント/サーバー環境用
C:\Program Files\Java\jdk1.8.0_25\db\lib\derbyclient.jar

組み込み環境(Embedded environment)は、ローカルにDBを用意し、1つのアプリケーションだけがDBにアクセスする方式。 同時に複数のアプリケーションから接続することは出来ない。
クライアント/サーバー環境(Client/server environment)は、DBをサーバーとして起動しておいて、同時に複数のアプリケーション(複数のユーザー)が(ネットワーク経由で)接続できる。

どちらの方式で接続するのかは、接続URLで指定する。

環境 接続URLの例 使用されるドライバー 必要なjarファイル
組み込み環境 jdbc:derby:C:/temp/javadb/sample1 org.apache.derby.jdbc.EmbeddedDriver derby.jar
クライアント/サーバー環境 jdbc:derby://localhost/C:/temp/javadb/sample1
jdbc:derby://localhost:1527/C:/temp/javadb/sample1
org.apache.derby.jdbc.ClientDriver derby.jar
derbyclient.jar
両方 同上 org.apache.derby.jdbc.AutoloadedDriver derby.jar
derbyclient.jar

EmbeddedDriverはderby.jarに入っていてClientDriverはderbyclient.jarに入っている。
組み込み環境で使用する場合はderby.jarだけあれば良いが、クライアント/サーバー環境で使用する場合はderby.jarとderbyclient.jarの両方が必要。

クライアント/サーバー環境用のJavaDBの起動方法


JavaDBの作成・接続

JavaDBは、接続時にJavaDBの場所を指定する。
このとき、「create=true」というオプションを付けていれば、DBが存在しない場合に自動的に最低限必要なテーブル・データが作成される。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
	public static void main(String[] args) throws SQLException {
		Connection conn;
		try {
			conn = DriverManager.getConnection(
				"jdbc:derby:C:/temp/javadb/sample1;create=true"
			);
		} catch(SQLException se) {
			for (SQLException e = se; e != null; e = e.getNextException()) {
				System.err.printf("%s: %s%n", e.getSQLState(), e.getMessage());
			}
			throw se;
		}
		conn.close();
	}

Class.forName("org.apache.derby.jdbc.EmbeddedDriver");」というドライバー指定を最初に書いてもいいが、これはJDBC3.0の書式
JavaDBはJDBC4.0(JDK1.6以降)に対応しているので、特に書く必要は無い。
(→ドライバークラスを直接指定して接続する方法

コネクションURLの先頭は「jdbc:derby:」(プロトコルとサブプロトコル)で固定。

その後にDBの場所(パス)を書く。上記の例では「C:\temp\javadb\sample1」。
もし「sample1」の様に書くと、相対パスとして認識される。つまり実行時のカレントディレクトリー直下のsample1を指定したことになる。

この後にセミコロン「;」で区切って「create=true」を付けると、DBが存在していない場合に自動的に作られる。
(他の属性を複数指定する場合も、全てセミコロンで区切る)
属性をURLに直接指定せず、プロパティーを使用する方法

上記の例では、「C:\temp\javadb\sample1」というディレクトリーが作られ、その下に色々なファイルが置かれる。
(したがってDBを削除したい場合は、そのディレクトリーをただ削除すればよい)


createを指定しないか「create=false」を指定すると、DBが存在していない場合は以下のような例外が発生する。

Exception in thread "main" java.sql.SQLException: データベース 'C:/temp/javadb/sample1' が見つかりません。

DBが存在していても、他のツール(ij.batEclipseのプラグイン等)がDBを開いていると、アプリケーションから接続することが出来ず、以下のようなエラーになる。
組込環境では、同時には1つのアプリケーションしかDBに接続できない為)

XJ040: データベース 'C:/temp/javadb/sample1' を始動できません。詳しくは、次の例外を参照してください。
XSDB6: Derby の別のインスタンスがすでにデータベース C:\temp\javadb\sample1 をブートしている可能性があります。

なお、「次の例外」という言葉は、SQLException#getNextException()によって取得される例外のことを指しているような気がする。
普通はException#getCause()によって取得できるべきだと思うんだけど、何でこうなってるんだろう…?

ついでに。間違ってセミコロンじゃなくてクエスチョン「?」で区切ったら、以下のようなエラーになった(爆)

XJ040: データベース 'C:/temp/javadb/sample1?create=true' を始動できません。詳しくは、次の例外を参照してください。
XJ001: Java 例外: 'Invalid argument: java.io.IOException'。

そういうミスをしない為には、プロパティーを使って指定した方がいいかも。(ちゃんとコピペしてれば、そーゆーミスはしないはずだけど(苦笑))

	public static void main(String[] args) throws SQLException {
		Properties info = new Properties();
		info.put("create", "true");
		Connection conn = DriverManager.getConnection(
			"jdbc:derby:C:/temp/javadb/sample1", info
		);
		conn.close();
	}

「create=true」を指定していてDBが既に存在している場合、エラーにはならない(例外は発生しない)。
DBが既に存在していたかどうか知りたかったら、SQLWarningが使える。

import java.sql.SQLWarning;
		Connection conn = DriverManager.getConnection(〜);
		SQLWarning w = conn.getWarnings();
		for (SQLException e = w; e != null; e = e.getNextException()) {
			System.out.printf("%s: %s%n", e.getSQLState(), e.getMessage());
		}

初めてDBを作った場合はgetWarnings()はnullを返すが、既存だった場合は以下のような警告が返ってくる。

01J01: データベース 'C:/temp/javadb/sample1' は作成されませんでした。代わりに既存のデータベースに接続されました。

DBのユーザー名やパスワードを指定する場合は以下の様にする。

		Connection conn = DriverManager.getConnection(
			"jdbc:derby:C:/temp/javadb/sample1;create=true",
			"ユーザー名", "パスワード"
		);
		Properties info = new Properties();
		info.setProperty("user", "ユーザー名");
		info.setProperty("password", "パスワード");
		Connection conn = DriverManager.getConnection(
			"jdbc:derby:C:/temp/javadb/sample1;create=true",
			info
		);
		Properties info = new Properties();
		info.setProperty("create", "true");
		info.setProperty("user", "ユーザー名");
		info.setProperty("password", "パスワード");
		Connection conn = DriverManager.getConnection(
			"jdbc:derby:C:/temp/javadb/sample1", info
		);
		Connection conn = DriverManager.getConnection(
			"jdbc:derby:C:/temp/javadb/sample1;create=true;user=ユーザー名;password=パスワード"
		);

ユーザー名を省略した場合は、「APP」というユーザー(スキーマ)を指定したのと同じ扱いになっている。


クライアント/サーバー環境

クライアント/サーバー環境でJavaDBを使う場合は、接続URLにホスト名(IPアドレス)(とポート番号)を指定する。

		Connection conn;
		try {
			conn = DriverManager.getConnection(
				"jdbc:derby://localhost/C:/temp/javadb/sample1;create=true"
		//		"jdbc:derby://localhost:1527/C:/temp/javadb/sample1;create=true"
			);
		} catch(SQLException se) {
			for (SQLException e = se; e != null; e = e.getNextException()) {
				System.err.printf("%s: %s%n", e.getSQLState(), e.getMessage());
			}
			throw se;
		}

また、derby.jarの他にderbyclient.jarが必要。
とは言っても実行時にドライバーを探しにいくから必要なので、コンパイル時のクラスパスにはderbyclient.jarは不要ではある。
derbyclient.jarが実行時のクラスパスに入っていない場合、以下のようなエラーが発生する。

08001: No suitable driver found for jdbc:derby://localhost/C:/temp/javadb/sample1

クライアント/サーバー環境でJavaDBを使う場合、別途JavaDBを起動しておく必要がある。
起動していないのに接続しようとした場合、以下のようなエラーが発生する。

08001: java.net.ConnectException : Error connecting to server localhost on port 1527 with message Connection refused: connect.

サーバー用のJavaDBを起動させる為には、以下のようにコマンドを実行する。

●JDK1.6.0(_02より前)
> set DERBY_HOME=C:\Program Files\Java\jdk1.6.0\db
> path=%PATH%;%DERBY_HOME%\frameworks\NetworkServer\bin
> start startNetworkServer.bat
●JDK1.6.0_02以降 [2009-04-23]
> path=%PATH%;C:\Program Files\Sun\JavaDB\bin
> start startNetworkServer.bat

これで、別のウィンドウ(コマンドプロンプト)が起ち上がり、JavaDBが稼動し始める。
終了させるには、そのウィンドウを閉じればよい。

停止用にstopNetworkServer.batというのもあるのだが、JDK1.6.0(_02より前)では、実行するとエラーになる(苦笑)
(JDK1.6.0_02以降では、ちゃんと動く。[2009-04-23]

> stopNetworkServer.bat
'C:\Program' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

バッチファイル内にjavaコマンドを実行する箇所があるのだが、そこがダブルクォーテーションで囲まれていない為。
修正すれば動くようになる。(startのバッチの方はそういう風になっている…つまり、stopのバッチなんて誰も使ってなかったという事か(爆))

@REM ---------------------------------------------------------
@REM -- shutdown Derby as a Network server
@REM ---------------------------------------------------------
%JAVA_HOME%\bin\java -cp "%DERBY_HOME%\lib\derby.jar;〜
↓
"%JAVA_HOME%\bin\java" -cp "%DERBY_HOME%\lib\derby.jar;〜

環境変数JAVA_HOMEは、JDK1.6のディレクトリーを指している想定


DBの終了(シャットダウン)

接続によって取得したコネクションをクローズするだけでは、DBへの接続は終了しない。[2009-12-25]
明示的にシャットダウンしてやる必要がある。

	private void shutdown() throws SQLException {
		DriverManager.getConnection("jdbc:derby:;shutdown=true");
	}
	private void shutdown() throws SQLException {
		Properties info = new Properties();
		info.setProperty("shutdown", Boolean.toString(true));
		DriverManager.getConnection("jdbc:derby:", info);
	}

ドライバークラスを直接使う場合もconnect()メソッドに同様の引数を渡せばよい。


シャットダウンが成功すると例外が必ず発生するので、エラーコードをチェックするのが正しい姿勢かな?

		try {
			shutdown();
			throw new SQLException("切断されなかった!");
		} catch (SQLException se) {
			if ("XJ015".equals(se.getSQLState())) {
				//正常にシャットダウンされた
				se.printStackTrace();
			} else {
				//シャットダウン失敗
				throw se;
			}
		}

↓シャットダウンが成功した場合のスタックトレース

java.sql.SQLException: Derby システムがシャットダウンされました。
	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
	at org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
	at org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
〜
	at jp.hishidama.sample.ConnManager.shutdown(ConnManager.java:91)
	at jp.hishidama.sample.JavaDBSample.main(JavaDBSample.java:37)
Caused by: java.sql.SQLException: Derby システムがシャットダウンされました。
	at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
	... 8 more

2つ以上のDBに接続している場合、「jdbc:derby:;shutdown=true」だと、全てのDBがシャットダウンされる。

明示的に1つのDBを指定すれば、そのDBだけシャットダウンされる。
その場合、エラーコードはXJ015でなく08006になるようだ。

		try {
			DriverManager.getConnection("jdbc:derby:C:/temp/javadb/sample1;shutdown=true");
			throw new SQLException("切断されなかった!");
		} catch (SQLException se) {
			if ("08006".equals(se.getSQLState())) {
				//正常にシャットダウンされた
				se.printStackTrace();
			} else {
				//シャットダウン失敗
				throw se;
			}
		}

java.sql.SQLNonTransientConnectionException: データベース 'C:/temp/javadb/sample1' がシャットダウンされました。
	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
〜
	at jp.hishidama.sample.ConnManager.shutdown(ConnManager.java:94)
	at jp.hishidama.sample.JavaDBSample.main(SampleMain.java:38)
Caused by: java.sql.SQLException: データベース 'C:/temp/javadb/sample1' がシャットダウンされました。
	at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
	... 13 more
Caused by: ERROR 08006: データベース 'C:/temp/javadb/sample1' がシャットダウンされました。
	at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
	at org.apache.derby.impl.jdbc.TransactionResourceImpl.shutdownDatabaseException(Unknown Source)
	... 8 more
コード エラーメッセージ例 概要
XJ015 java.sql.SQLException: Derby システムがシャットダウンされました。 JavaDBの接続全てを正常にシャットダウンした。
08006 java.sql.SQLNonTransientConnectionException: データベース 'C:/temp/javadb/sample1' がシャットダウンされました。 特定のDBに対する接続を正常にシャットダウンした。(組込環境
java.sql.SQLNonTransientConnectionException: DERBY SQL error: SQLCODE: -1, SQLSTATE: 08006, SQLERRMC: データベース 'C:/temp/javadb/sample1' がシャットダウンされました。 特定のDBに対する接続を正常にシャットダウンした。(ネットワーク接続
XJ004 データベース 'C:/temp/javadb/sample2' が見つかりません。 一度も接続していないDBをシャットダウンしようとした。
あるいは、シャットダウンしたDBを再度シャットダウンしようとした。
あるいは、本当に存在しないDB名を指定している。
(null) java.sql.SQLException: org.apache.derby.jdbc.EmbeddedDriver は、JDBC ドライバー・マネージャーに登録されていません JavaDB全体をシャットダウンした後で再度(全体あるいは特定のDBを)シャットダウンしようとした。

組込環境でJavaDBに接続するツールでは、コネクションを切断(disconnect・Connection#close())したがツール自体は稼動し続けている場合、他のツールからそのDBに接続できないことがよくある。
これは、そのツールが上記の「シャットダウン」を行っていない為に起きているようだ。
きちんとシャットダウンしてやれば、ツール自体は動き続けていても他のツールからDB接続できるようになる。

接続 シャットダウン 解説
c1 = DriverManager.getConnection("jdbc:derby:C:/temp/havadb/sample1"); DriverManager.getConnection("jdbc:derby:;shutdown=true"); 他のツールからsample1に接続できるようになる。
c1 = DriverManager.getConnection("jdbc:derby:C:/temp/havadb/sample1");
c2 = DriverManager.getConnection("jdbc:derby:C:/temp/havadb/sample2");
DriverManager.getConnection("jdbc:derby:;shutdown=true"); 他のツールからsample1・sample2に接続できるようになる。
DriverManager.getConnection("jdbc:derby:C:/temp/havadb/sample1;shutdown=true"); 他のツールからsample1に接続できるようになるが、sample2には接続できない。
DriverManager.getConnection("jdbc:derby:C:/temp/havadb/sample1;shutdown=true");
DriverManager.getConnection("jdbc:derby:C:/temp/havadb/sample2;shutdown=true");
他のツールからsample1・sample2に接続できるようになる。

derby.logの場所

JavaDBを使うと、カレントディレクトリーの下にderby.logというファイルが作られる。[2011-08-13]
これを任意の場所に出力する為にはシステムプロパティーでderby.stream.error.fileを設定する。

> java -Dderby.stream.error.file=C:/temp/derby.log 実行するクラス 〜

参考: abetuyoさんのJavaDBの使い方


テーブルの作成

他の(Derby以外の)JDBC接続と同様にSQLを実行できる。

例えばテーブルを作るには、以下のようにする。

		try {
			Statement stat = conn.createStatement();
			try {
				stat.execute("create table test( id numeric(4),name varchar(10) )");
			} catch (SQLException se) {
				for (SQLException e = se; e != null; e = e.getNextException()) {
					System.err.printf("%s: %s%n", e.getSQLState(), e.getMessage());
				}
				throw se;
			} finally {
				stat.close();
			}
		} finally {
			conn.close();
		}

CREATE TABLEの文法
APIを使ってもうちょっと汎用的にテーブルを作成する例


トランザクション制御(コミットとロールバック)

デフォルトでは、JavaDBのコネクションは自動コミットがONになっているようだ。(JavaDBに限らず、JDBCのデフォルトらしい?)
つまり、SQLを実行する度に自動的にコミットされる。

トランザクション制御を自分で行う場合は、以下のようにする。

		conn.setAutoCommit(false);
		try {
			insertSample(conn);
			conn.commit();
		} catch (SQLException e) {
			conn.rollback();
			throw e;
		} finally {
			conn.close();
		}

※close()時点でcommit()もrollback()も呼ばれていないと、例外が発生する。

java.sql.SQLException: 無効なトランザクション状態です。

コンソールツール

JavaDBにコンソールからコマンドを入力してアクセスするツールも用意されている。 [/2009-12-25]
(OracleでいうSQL*Plusのようなもの)

ijの使用方法


バージョン確認

JavaDB(derby)のバージョンは、sysinfoというコマンド(バッチ)で確認できる。[2009-02-23]
これはijと同じ場所に入っている。

JDK1.6.0(_02より前)の場合:

> set DERBY_HOME=C:\Program Files\Java\jdk1.6.0\db
> path=%PATH%;%DERBY_HOME%\frameworks\embedded\bin
> sysinfo.bat
〜
--------- Derby 情報 --------
JRE - JDBC: Java SE 6 - JDBC 4.0
[C:\Program Files\Java\jdk1.6.0\db\lib\derby.jar] 10.2.1.7 - (453926)
[C:\Program Files\Java\jdk1.6.0\db\lib\derbytools.jar] 10.2.1.7 - (453926)
------------------------------------------------------
〜

JDK1.6.0_02以降の場合: [2009-04-23]

> path=%PATH%;C:\Program Files\Sun\JavaDB\bin
> sysinfo.bat
〜
--------- Derby 情報 --------
JRE - JDBC: Java SE 6 - JDBC 4.0
[C:\Program Files\Sun\JavaDB\lib\derby.jar] 10.4.1.3 - (648739)
[C:\Program Files\Sun\JavaDB\lib\derbytools.jar] 10.4.1.3 - (648739)
[C:\Program Files\Sun\JavaDB\lib\derbynet.jar] 10.4.1.3 - (648739)
[C:\Program Files\Sun\JavaDB\lib\derbyclient.jar] 10.4.1.3 - (648739)
------------------------------------------------------
〜

Java目次へ戻る / JDBCへ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま