2014年12月23日火曜日

H2データベースでテーブルが存在しない時だけテーブルを作成

H2データベースでテーブルが存在しない時だけテーブルを作成する方法です。

CREATE時に、IF NOT EXISTSを使用することで、テーブルが存在しない時のみ作成することができます。
これを使うことで、テーブル定義済み例外の発生を防ぐことができます。

CREATE TABLE IF NOT EXISTS USER (
  ID BIGINT NOT NULL AUTO_INCREMENT,
  NAME VARCHAR(100 CHAR) NOT NULL,
  PRIMARY KEY (ID)
);

このIF NOT EXISTSはVIEWの作成やカラムの追加時などにも使用できます。

2014年12月22日月曜日

[Oracle12c]generatedカラムの値をJDBC経由でinsert後に取得する

Oracle12cで追加された自動生成カラムの値を、JDBC経由でINSERTを行った際に取得する方法です。

コードサンプル

テーブル定義

CREATE TABLE USER_INFO
(
    ID INTEGER PRIMARY KEY NOT NULL,
    NAME VARCHAR2(100)
)

Javaコード

PreparedStatement statement = connection
        .prepareStatement(
                "insert into USER_INFO (name) values (?)",
                new String[]{"id"});
statement.setString(1, "なまえ");
int count = statement.executeUpdate();
System.out.println("count = " + count);

try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
    if (generatedKeys.next()) {
        System.out.println(generatedKeys.getInt(1));
    }
}

解説

PreparedStatement生成時に、自動生成キーを返す機能を持つPreparedStatementを生成します。
上のサンプルでは、自動生成カラムはID列なので、prepareStatementの2番めの引数にID列を指定しています。

必要な値をバインド後に、executeUpdateを呼び出してINSERT処理を実行します。

INSERT処理が正常に終了後、getGeneratedKeysを呼び出して、自動生成カラムに対して自動的に採番されて設定された値を取得します。
getGeneratedKeysは、ResultSetを返すのでフェッチ(nextメソッドの呼び出し)しながら値を取得していきます。
Oracleでは、getGeneratedKeysで返されるResultSetからの値の取得はインデックスのみ可能なので、カラム名によるアクセスは出来ません。

[Java8]インタフェースのデフォルトメソッド

Java8から新しく追加されたインタフェースのデフォルトメソッド。

デフォルトメソッドの定義

デフォルトメソッドは、defaultキーワードと共にメソッドを宣言します。
この例では、printメソッドがデフォルトメソッドとして宣言されています。
interface Hoge {
    default void print() {
        System.out.println("hoge");
    }
}

同じデフォルトメソッドを持つ複数のインタフェースを実装した場合

何もしなければコンパイルエラーとなります。
例えば、下のコードではImplクラスが同じ定義のデフォルトメソッドを持つI1とI2インターフェースを実装しているので、コンパイル時にエラーとして報告されます。
interface I1 {
    default void print() {
        System.out.println("I1");
    }
}
interface I2 {
    default void print() {
        System.out.println("I2");
    }
}

class Impl implements I1, I2 {
}

もしどちらか一方の実装を使用したいのであれば、superキーワードを使用して一方のインタフェースの実装を選択します。
下の例では、I2インタフェースのデフォルト実装を選択しています。
class Impl implements I1, I2 {
    @Override
    public void print() {
        I2.super.print();
    }
}

もちろん、下のコードのように実装を上書きすることもできます。
class Impl implements I1, I2 {
    @Override
    public void print() {
        System.out.println("Impl");
    }
}

片方がデフォルトメソッドで片方が抽象メソッドの場合も、コンパイルエラーとなります。
この場合も、上で説明したようにデフォルトメソッドを選択するか、このクラスで新たな実装をするか選択する必要があります。
interface I1 {
    default void print() {
        System.out.println("I1");
    }
}
interface I2 {
    void print();
}

class Impl implements I1, I2 {
}

一方が抽象クラスの場合には、抽象クラスに定義されたメソッドが優先されて選択されます。
例えば下のコードの場合、A1抽象クラスに定義されたprintメソッドが呼び出されます。
interface I1 {
    default void print() {
        System.out.println("I1");
    }
}

abstract class A1 {
    public void print() {
        System.out.println("A1");
    }
}

class Impl extends A1 implements I1 {
}