サイトアイコン たーちゃんの「ゼロよりはいくらかましな」

【JavaDB】derbyをインメモリDBとして使用する

JavaDBは、Apache Derbyというデータベースを

Oracleがサポートすることでjava標準でJDK1.6以降に追加されました。

 

 

なんですが、今回(2019年4月現在)サンプルを作成しようとしたところ、

derbyのライブラリが見当たらない・・・・。

どうやらこちらをみると最近は同梱されなくなったみたいですね・・・。

※情報ありがとうございます!

java標準なので!ということで採用するという力技は難しくなっちゃいました笑

 

 

本来は[jdk_home]/db/ibの配下にderby.jarが同梱されています。

※今僕が使用しているpleiades(eclipse ver4.10.0)では、javaは

6、7、8、11と入っていますが実際derby.jarが同梱されているのは、

7のみでした。

 

 

ただ、実際にプロジェクトなんかで使用する時は、

javaの標準ではクラスパス通ってないので、

結局mavenのリポジトリ参照するということが必要になります。

 

 

同梱されているだけでは、そのまま使えませんよという感じです。

なので、同梱されなくなりましたというのも

わからない話ではないかなといった印象ですが・・・。

 

 

さて、ここからが本題。

derbyはもちろん永続化されたDBとしても利用できますが、

インメモリで使用することができます。

 

 

おそらくそのあたりを狙ってか、

mavenのセントラルリポジトリでpomを確認すると、

scopeはtestになってますね。

 

 

jenkinsなどのCI利用を考えると、

永続化DBに接続はさせられないので、

インメモリで使用させたいってことなのでしょうか??

 

では、実際にその使用方法について書いていきたいと思います。

今回はmavenプロジェクトで実施します。

 

 

 

derby事前準備

今回は同梱されたderby.jarではなく、

mavenセントラルリポジトリから参照することにします。

 

 

pomに以下のように依存関係を追加します。

準備はこれだけです。

		<dependency>
			<groupId>org.apache.derby</groupId>
			<artifactId>derby</artifactId>
			<version>10.14.2.0</version>
		</dependency>

 

 

※2019年4月現在、最新のversionは10.15.1.3なのですが、

これを依存関係に追加してしまうと、以下のExceptionによりうまく動作しません。

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/derby/shared/common/security/SystemPermission
	at org.apache.derby.iapi.jdbc.AutoloadedDriver.connect(AutoloadedDriver.java:134)
	at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677)
	at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:251)
	at jp.co.tarchan.derbysample.DerbySample.main(DerbySample.java:16)
Caused by: java.lang.ClassNotFoundException: org.apache.derby.shared.common.security.SystemPermission
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	... 4 more

 

 

ClassNotFoundなのですが、jarの中には確かに指定されたclassが無いので、

バグなのかしら?と思っております。

なので、今回はその1つ前のversionである10.14.2.0を使用することにしました。

 

 

使用サンプル

まずはサンプルコードを。

package jp.co.tarchan.derbysample;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 * Derby接続サンプル.
 */
public class DerbySample {

    /**
     * 主処理.
     * @param args 実行引数
     */
    public static void main(String[] args) {

        // インメモリとして使用するDerbyのDBを作成する
        try (Connection conn = DriverManager.getConnection("jdbc:derby:memory:TestDB;create=true");
                Statement stmt = conn.createStatement();) {

            // テーブルをcreateする
            StringBuilder sb = new StringBuilder();
            sb.append("CREATE TABLE TEST_USER (");
            sb.append("    USER_ID VARCHAR(10) PRIMARY KEY,");
            sb.append("    USER_NAME VARCHAR(50))");

            stmt.executeUpdate(sb.toString());

            // データを1件insert
            sb = new StringBuilder();
            sb.append("INSERT INTO TEST_USER (");
            sb.append("    USER_ID,");
            sb.append("    USER_NAME");
            sb.append(") VALUES (");
            sb.append("    'ABC1234567',");
            sb.append("    'テスト太郎')");

            stmt.executeUpdate(sb.toString());

            // データをselect
            sb = new StringBuilder();
            sb.append("SELECT * FROM TEST_USER");

            ResultSet rs = stmt.executeQuery(sb.toString());

            while (rs.next()) {
                System.out.println(rs.getString("USER_ID"));
                System.out.println(rs.getString("USER_NAME"));
            }

        } catch (Exception e) {

            e.printStackTrace();

        }
    }
}

 

 

解説

Connection作成のときのURL(jdbc:derby:memory:TestDB;create=true)これで

メモリ上にTestDBというDBが作成されます。

この時、create=trueとすることで、存在しなければ作成という挙動になります。

 

接続が確立された後は、通常のjdbcを使用した接続と大きく変わることは

ありません。

 

テーブル作成の時のカラム型はこちら

 

 

おまけ(インメモリ使用しない場合)

今回はderbyをインメモリで使用するサンプルについて

お話しましたが、では永続的なDBとして使用する場合はどうするのか?

というのをおまけとしてお話したいと思います。

 

 

記述の違いはjdbcURLのみ

永続的に使用する場合のインメモリとの違いはjdbcのURLのみで可能です。

 

記述の違いは以下です。

 

jdbc:derby:memory:TestDB;create=true

 

 

jdbc:derby:C:/test/TestDB;create=true

 

ここで注意することがあります。

指定するフォルダは中身のあるフォルダではいけません

また、存在してもいけません

 

あくまで最後のTestDBはDB名なので、

事前にそのフォルダが存在すると、エラーとなります。

 

動作確認

永続化するということは、2度テーブル作成したりできないということになりますね。

ということで同じプログラムを2度実施してみました。

 

するとこんなエラーになります。

 

java.sql.SQLException: Table/View 'TEST_USER' already exists in Schema 'APP'.
	at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
	at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
	at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedStatement.executeLargeUpdate(Unknown Source)
	at org.apache.derby.impl.jdbc.EmbedStatement.executeUpdate(Unknown Source)
	at jp.co.tarchan.derbysample.DerbySample.main(DerbySample.java:29)
Caused by: ERROR X0Y32: Table/View 'TEST_USER' already exists in Schema 'APP'.
	at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
	at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
	at org.apache.derby.impl.sql.catalog.DataDictionaryImpl.duplicateDescriptorException(Unknown Source)
	at org.apache.derby.impl.sql.catalog.DataDictionaryImpl.addDescriptor(Unknown Source)
	at org.apache.derby.impl.sql.execute.CreateTableConstantAction.executeConstantAction(Unknown Source)
	at org.apache.derby.impl.sql.execute.MiscResultSet.open(Unknown Source)
	at org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(Unknown Source)
	at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
	... 5 more

 

APPというスキーマにはTEST_USERというテーブルはすでに存在していますよ。となっていますね。想定通りですね。

 

ちなみに、今回のサンプルではユーザ・パス・スキーマすべてデフォルトになるので、

その場合はderbyではAPPというスキーマ、APPというユーザ、APPというパスワードとなります。

 

次回はderbyとjpaを組み合わせてテストを実施することについて

お話したいと思います。

 

それでは!

 


にほんブログ村


人気ブログランキング

モバイルバージョンを終了