Mar 12, 2006

[Derby] Derby を Tomcat 5.5 の DataSource に設定する方法

Server Mode で起動した Derby を Tomcat 5.5 に DataSource として登録する方法をメモ。 Tomcat 5.0 → 5.5 で設定方法が変わったことで、意外と設定に時間がかかってしまった。

The Apache Tomcat 5.5 Servlet/JSP Container JNDI Datasource HOW-TO
http://tomcat.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto.html

Derby を Server Mode で起動

Derby 10.1.2.1 を前提とする。

> set JAVA_HOME=c:\jdk1.5.0_06
> set DERBY_INSTALL=c:\db-derby-10.1.2.1-bin
> cd db-derby-10.1.2.1-bin\frameworks\NetworkServer\bin
db-derby-10.1.2.1-bin\frameworks\NetworkServer\bin>startNetworkServer.bat
サーバーは、ポート 1527 で接続を受け入れる準備ができました。

Tomcat 5.5 の設定

Tomcat 5.5.15 を前提とする。

  1. Tomcat に Derby の JDBC ドライバを登録する。 derbyclient.jar、derbynet.jar、derbytools.jar を %CATALINA_HOME%/common/lib/ にコピーする。
  2. DataSource の設定を行う。 %CATALINA_HOME%/conf/server.xml に下記の設定を追加する。
    <Host name="localhost" 
          appBase="webapps"
          unpackWARs="true" 
          autoDeploy="true"
          xmlValidation="false" 
          xmlNamespaceAware="false">
    
      <Context path="/myapp" 
               docBase="myapp"
               reloadable="false" 
               crossContext="true">
    
        <Resource name="jdbc/TestDB" 
                  auth="Container" 
                  type="javax.sql.DataSource"
                  driverClassName="org.apache.derby.jdbc.ClientDriver"
                  url="jdbc:derby://localhost:1527/derbyDB;create=true"/>
      </Context>
    <Host>
    
ちなみに、Host → Context → Resource という階層構造にしないと、何故か url や driverClassName が設定されないために
Cannot create JDBC driver of class '' for connect URL 'null' java.sql.SQLException: No suitable driver
という例外が発生する。

Web アプリケーションの設定

<web-app>
  <resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/TestDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>
</web-app>

アプリケーションからの呼び出し

普通に JNDI 経由で DataSource を取得すれば良い。

Context context = new InitialContext();
Object obj = context.lookup("java:comp/env/jdbc/TestDB");
DataSource dataSource  = (DataSource)obj;
Connection connection = dataSource.getConnection();

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Feb 23, 2006

[Derby] Derby メモ(3)

Derby のパフォーマンスに関するリファレンスをメモ。 「Derby ならでは」というものは少ない。 システムのプロパティ(derby.storage.pageCacheSize、derby.storage.pageReservedSpace、derby.storage.pageSize)くらいか。

Performance tips and tricks
http://db.apache.org/derby/docs/10.0/manuals/tuning/perf19.html
derby.storage.pageCacheSize
http://db.apache.org/derby/docs/10.1/tuning/tuning-single#N18B49
derby.storage.pageReservedSpace
http://db.apache.org/derby/docs/10.1/tuning/tuning-single#N18D9B
derby.storage.pageSize
http://db.apache.org/derby/docs/10.1/tuning/tuning-single#N18FFB

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Feb 09, 2006

[Derby] Derby メモ(2)

Derby を使った Java 開発に必要な情報をメモ。

Derby Reference Manual
http://db.apache.org/derby/docs/10.1/ref/
Statements
http://db.apache.org/derby/docs/10.1/ref/crefsqlj39374.html
DataTypes
http://db.apache.org/derby/docs/10.1/ref/crefsqlj31068.html
Derby System Tables
http://db.apache.org/derby/docs/10.1/ref/rrefsistabs38369.html

Derby データ型 <-> Java データ型のマッピング

Derby と Java のデータ型のマッピングを一覧表にしたものが欲しかったのだが、探した限りでは見つからなかったので自作してみた。 とは言っても、↑の DataTypes の内容を表形式にしただけのオソマツなもの。 個人的にはこれで十分だが。

Syntax Corresponding compile-time Java type JDBC metadata type (java.sql.Types) 備考
BIGINT java.lang.Long BIGINT -9223372036854775808 (java.lang.Long.MIN_VALUE) ~ 9223372036854775807 (java.lang.Long.MAX_VALUE)
{ BLOB | BINARY LARGE OBJECT } ( length [{K |M |G }])) java.sql.Blob BLOB K(1024), M(1024 * 1024), G(1024 * 1024 * 1024)
CHAR[ACTER] [(length)] java.lang.String CHAR
{ CHAR | CHARACTER }[(length)] FOR BIT DATA - BINARY
{CLOB |CHARACTER LARGE OBJECT}(length [{{K |M |G}])) java.sql.Clob CLOB K(1024), M(1024 * 1024), G(1024 * 1024 * 1024)
DATE java.sql.Date DATE サポートするフォーマットは
  • yyyy-mm-dd
  • mm/dd/yyyy
  • dd.mm.yyyy
{ DECIMAL | DEC } [(precision [, scale ])] java.math.BigDecimal DECIMAL
{ DOUBLE PRECISION | DOUBLE } java.lang.Double DOUBLE precision は 1 ~ 31。scale は precision 以下。
FLOAT [ (precision) ] - REAL or DOUBLE
{ INTEGER | INT } java.lang.Integer INTEGER -2147483648 (java.lang.Integer.MIN_VALUE) ~ 2147483647 (java.lang.Integer.MAX_VALUE)
LONG VARCHAR java.lang.String LONGVARCHAR
LONG VARCHAR FOR BIT DATA - -
NUMERIC [(precision [, scale ])] java.math.BigDecimal NUMERIC
REAL java.lang.Float REAL
SMALLINT java.lang.Short SMALLINT -32768 (java.lang.Short.MIN_VALUE) ~ 32767 (java.lang.Short.MAX_VALUE)
TIME java.sql.Time TIME サポートするフォーマットは
  • hh:mm[:ss]
  • hh.mm[.ss]
  • hh[:mm] {AM | PM}
TIMESTAMP java.sql.Timestamp TIMESTAMP サポートするフォーマットは
  • yyyy-mm-dd hh[:mm[:ss[.nnnnnn]]]
  • yyyy-mm-dd-hh[.mm[.ss[.nnnnnn]]]
{ VARCHAR | CHAR VARYING | CHARACTER VARYING }(length) java.lang.String VARCHAR The maximum length for a VARCHAR string is 32,672 characters.
{ VARCHAR | CHAR VARYING | CHARACTER VARYING } (length) FOR BIT DATA - VARBINARY The maximum size of the length value is 32,672 bytes.

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 28, 2005

[Derby] Derby の実行速度

Derby の INSERT 速度を試してみた。 時間がなかったのでかなりいい加減。 非常に単純な INSERT 文を 100 万回繰り返してみた。

結果


embedded モード server モード
INSERT 1000000回
コネクション毎に 1000000 件ずつ 1 回繰り返し
45406msec (≒45秒) 320594msec (≒5分)
INSERT 1000000回
コネクション毎に 1000 件ずつ 1000 回繰り返し
51797msec (≒52秒) 321812msec (≒5分)
INSERT 1000000回
コネクション毎に 1 件ずつ 1000000 回繰り返し
798422msec (≒13分) 計測不能(何故か Exception で落ちる)

環境

OS
Windows XP Professional
CPU
Pentium4 2.4GHz
Memory
1GByte

コード(部分抜粋)

    protected void insertRecordMassively1() throws SQLException {

        // 1 回のコネクションで 1000 件の INSERT を 1000 回繰り返す。
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            Connection connection = this.getConnection();
            try {
                PreparedStatement statement = connection
                        .prepareStatement("INSERT INTO sample VALUES (?,?)");

                for (int j = 0; j < 1000; j++) {
                    int field01 = (int) ((Math.random() * 100000) % 10000);
                    String field02 = "01:" + field01;
                    statement.setInt(1, field01);
                    statement.setString(2, field02);
                    statement.executeUpdate();
                }

                connection.commit();
                connection.close();

            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }
        long end = System.currentTimeMillis();

        System.out.println("INSERT * 1000 * 1000 : " + (end - start) + "msec");
    }

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 26, 2005

[Derby] Derby を server モードで起動

先日は Derby を embedded モードで起動したので、今回は server モードを試してみた。 server モードの場合も embedded モードとほとんど同一のコードで起動できた。 意外と簡単。 クライアント側も Driver と URL を変更したら何事も無く接続できた。

Derby の実行環境構築

Derby を Server モードで起動する場合、embedded モードで利用したもの + α の jar が必要になる。

  1. Derby(derby.jar、derbynet.jar、derbyclient.jar) をクラスパスに追加

サンプルコード

package jp.in_vitro.codelets.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;

import org.apache.derby.drda.NetworkServerControl;

public class Codelet3 {

    public Codelet3() {
        super();
    }

    public static void main(final String[] args) throws Exception {
        Codelet3 me = new Codelet3();
        me.execute();
    }

    protected void execute() throws Exception {

        // Derby の起動。
        DerbyServer server = new DerbyServer();
        server.start();
        while (!server.isInitialized()) {
            Thread.sleep(1000);
        }

        // ネットワーク(と言っても loopback)経由で Derby に接続。
        DerbyClient client = new DerbyClient();
        client.initializeClient();
        client.execute();

        // Derby の終了。
        server.stop();
    }

    public static class DerbyClient {
        private static final String DRIVER = "org.apache.derby.jdbc.ClientDriver";
        private static final String PROTOCOL = "jdbc:derby://localhost:1527/";

        public DerbyClient() throws ClassNotFoundException {
            super();
            this.initializeClient();
        }

        public void execute() throws SQLException {

            Connection connection = null;
            try {
                connection = this.getConnection();
                Statement statement = connection.createStatement();
                ResultSet rs = statement
                        .executeQuery("SELECT * FROM sys.systables");
                while (rs.next()) {
                    System.out.println("" + rs.getString(1));
                }

                rs.close();
                connection.commit();
                connection.close();

            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }

        protected void initializeClient() throws ClassNotFoundException {
            Class.forName(DRIVER);
        }

        protected Connection getConnection() throws SQLException {

            Connection connection = null;
            Properties props = new Properties();
            props.put("user", "me");
            props.put("password", "password");

            connection = DriverManager.getConnection(PROTOCOL
                    + "derbyDB;create=true", props);
            connection.setAutoCommit(false);

            return connection;
        }
    }

    public static class DerbyServer implements Runnable {
        private static final String DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
        private static final String PROTOCOL = "jdbc:derby:";
        private Thread thread;
        private boolean initialized;

        public DerbyServer() {
            super();
        }

        public void start() {
            if (this.thread == null) {
                this.thread = new Thread(this);
                this.thread.start();
            }
        }

        public void stop() {
            if (this.thread != null) {
                this.thread = null;
            }
        }

        public void run() {
            try {
                this.initializeDBMS();
                while (this.thread != null) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
                this.destroyDBMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public boolean isInitialized() {
            return this.initialized;
        }

        protected void initializeDBMS() throws Exception {

            System.setProperty("derby.drda.startNetworkServer", "true");
            Class.forName(DRIVER).newInstance();

            NetworkServerControl server = new NetworkServerControl();
            server.ping();

            this.initialized = true;
        }

        protected void destroyDBMS() throws SQLException {

            this.initialized = false;

            Connection connection = null;
            try {
                connection = DriverManager.getConnection(PROTOCOL
                        + ";shutdown=true");
                connection.commit();

            } catch (SQLException e) {
                // Derby が正常終了すると SQLException が発行される。
                System.out.println("" + e.getLocalizedMessage() + " : "
                        + e.getErrorCode());
            } finally {
                if (connection != null) {
                    connection.close();
                }
            }
        }
    }
}

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 20, 2005

[Derby] Derby メモ

Derby で調べた内容を少しだけメモ。 Derby 公式サイトにあるドキュメントを拾い集めただけ。

Derby environments

Derby には "embedded" モードと "server" モードで動作できる。 "embedded" モードはアプリケーション内部で起動されて、そのアプリケーション内でのみ使用可能なモード。"server" モードは単体でアプリケーションとして動作するモードで、複数のクライアントアプリケーションから使用可能。 コネクションの張り方やマルチスレッドなどで挙動が異なるらしい。

Environments in which Derby can run
http://db.apache.org/derby/docs/10.1/getstart/getstart-single.html#cgsquck70629
Connection Mode
http://db.apache.org/derby/docs/10.1/devguide/devguide-single.html#N16F6D

Derby Driver

Derby で使用できる JDBC ドライバは以下の 2 つ。

  • org.apache.derby.jdbc.EmbeddedDriver ・・・ "embedded" モード用ドライバ
  • org.apache.derby.jdbc.ClientDriver ・・・ "server" モード用ドライバ
Available drivers
http://db.apache.org/derby/docs/10.1/getstart/getstart-single.html#rgsquck35368

Database connection URL

URL の書式は以下の通り。

jdbc:derby://<server>[:<port>]/databaseName[;URLAttributes=<value> [;...]]
Database connection URL
http://db.apache.org/derby/docs/10.1/getstart/getstart-single.html#rgsquck30197

Derby プロパティ

Derby を実行する際に指定できるプロパティ一覧。

java -Dderby.system.home=c:\\derby ...
の様に JVM 起動時に指定するか、
Properties props = System.getProperties();
props.setProperty("derby.system.home", "c:\\derby");
の様にアプリケーション中から指定する。derby.properties という設定ファイルに記述することもできる。
Derby properties
http://db.apache.org/derby/docs/10.1/tuning/tuning-single#ctunproper22250

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |

Sep 19, 2005

[Derby] Derby にチャレンジ

Derby とは

Derby は 元 CloudScape と呼ばれた RDBMS。 IBM が Apache に寄贈したもの。 Pure Java で DBMS 自体のサイズが 2M と小さいのがステキ。

Derby
http://db.apache.org/derby/

Derby の実行環境構築

  1. Derby(derby.jar) をクラスパスに追加

サンプルコード

package jp.in_vitro.codelets.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 Codelet {

    private static final String DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";

    private static final String PROTOCOL = "jdbc:derby:";

    public Codelet() {
        super();
    }

    public static void main(final String[] args) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {

        Codelet me = new Codelet();
        me.execute();
    }

    protected void execute() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {

        // Derby を embedded モードで起動する。
        this.initializeDBMS();
        try {
            try {
                // テーブルの生成。
                this.createTable();
            } catch (SQLException e) {
                // 既に Table が生成済みの可能性があるので・・・
            }
            // insert
            this.insertRecord();
            // update
            this.updateRecord();
            // select
            this.selectRecord();
            // delete
            this.deleteRecord();
            // テーブルの削除。
            this.dropTable();
        } finally {
            // Derby のシャットダウン
            this.destroyDBMS();
        }
    }

    protected void initializeDBMS() throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {
        Class.forName(DRIVER).newInstance();

        Connection connection = null;
        try {
            connection = DriverManager.getConnection(PROTOCOL
                    + "derbyDB;create=true");
            connection.commit();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void destroyDBMS() throws SQLException {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(PROTOCOL
                    + ";shutdown=true");
            connection.commit();

        } catch (SQLException e) {
            // Derby が正常終了すると SQLException が発行される。
            System.out.println("" + e.getLocalizedMessage() + " : "
                    + e.getErrorCode());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected Connection getConnection() throws SQLException {

        Connection connection = null;
        Properties props = new Properties();
        props.put("user", "me");
        props.put("password", "password");

        connection = DriverManager.getConnection(PROTOCOL + "derbyDB", props);
        connection.setAutoCommit(false);

        return connection;
    }

    protected void createTable() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement
                    .executeUpdate("CREATE TABLE sample(field01 INT, field02 VARCHAR(10))");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void insertRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("INSERT INTO sample VALUES (999,'dummy data')");
            statement.executeUpdate("INSERT INTO sample VALUES (888,'hogehoge')");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void updateRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement
                    .executeUpdate("UPDATE sample SET field01=100 WHERE field02='dummy data'");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void deleteRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("DELETE FROM sample");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void selectRecord() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            ResultSet rs = statement
                    .executeQuery("SELECT * FROM sample ORDER BY field01");

            while (rs.next()) {
                System.out.println("field01=" + rs.getString(1) + ", field02="
                        + rs.getString(2));
            }

            rs.close();
            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    protected void dropTable() throws SQLException {

        Connection connection = this.getConnection();
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate("DROP TABLE sample");

            connection.commit();
            connection.close();

        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

}

Posted in Derby | このエントリーをはてなブックマークに追加 | この記事をクリップ! livedoor クリップ |