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 |
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の場所を指定する。
このとき、「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.bat
やEclipseのプラグイン等)が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への接続は終了しない。[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"); |
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"); |
他のツールからsample1・sample2に接続できるようになる。 |
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のようなもの)
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)
------------------------------------------------------
〜