2011年5月6日金曜日

JDBC経由でシーケンスを使用して採番した値の取得

insert文などでシーケンスを使用して採番を行った値を取得する場合、
JDBCの自動採番キー機能と、Oracleの拡張SQL文を使用する2パターンの方法がある。
Oracle拡張機能を使用した場合、1レコード更新なら良いが複数レコード更新になると、
クライアント側コードもOracleが拡張したJDBCの機能を使う必要があり、ちと面倒になる。

JDBCの自動採番キー機能

        // Statement取得時に、自動採番キーの項目を第二引数で指定する。
        // この例では、ID列がシーケンスでの採番対象なので『ID』と指定している。
        PreparedStatement statement = con.prepareStatement(
                "insert into test (ID, NAME) values (TEST_SEQ.nextval, ?)",
                new String[]{"ID"});
        try {
            statement.setString(1, "hogehoge");
            statement.execute();
            // SQLを実行後、statementオブジェクトからgetGeneratedKeysを呼び出して、
            // 採番キーの結果を取得する。(1行だけなのにResultSetってのが面倒・・・)
            ResultSet keys = statement.getGeneratedKeys();
            try {
                // ResultSetと同じ感じに値を取得する。
                // ただし、カラム名指定でのアクセスは出来ないので、
                // インデックス指定でアクセスする必要がある。
                keys.next();
                int id = keys.getInt(1);
                System.out.println("id = " + id);
            } finally {
                keys.close();
            }
        } finally {
            statement.close();
        }
        con.commit();
    }

Oracleの拡張SQL機能

        // Oracleで拡張された、returning intoを使用して、
        // IDカラムの値をバインド変数(OUTパラメータに代入する。)
        // なお、SQL文はbegin endで囲い、無名pl/sqlにする必要がある。
        CallableStatement statement = con.prepareCall(
                "begin insert into test (ID, NAME) "
                        + " values (TEST_SEQ.nextval, ?) returning id into ?; end;");

        try {
            statement.setString(1, "hoge");
            // OUTパラメータのタイプを指定する。
            statement.registerOutParameter(2, Types.INTEGER);
            statement.execute();
            // SQL実行後に、OUTパラメータの値を取得する。
            int id = statement.getInt(2);
            System.out.println("id = " + id);
            con.commit();
        } finally {
            statement.close();
        }

Oracleの拡張SQL機能で複数行更新の場合

        // returning intoを使用してID列をOUTパラメータに代入する。
        // SQL文は、通常のSQL文形式で、statementはOracleJDBCのstatementにキャストする。
        OracleCallableStatement statement = (OracleCallableStatement)
                con.prepareCall("update test set id = test_seq.nextval returning id into ?");
        try {
            // registerReturnParameterを呼び出して、データ型を設定する。
            // なお、この時に設定するデータ型はOracleTypesがもつ定数を使用する。
            statement.registerReturnParameter(1, OracleTypes.INTEGER);
            int count = statement.executeUpdate();
            System.out.println("count = " + count);

            // getReturnResultSetを呼び出して、OUTパラメータの結果セット(ResultSet)を取得する。
            ResultSet set = statement.getReturnResultSet();
            try {
                while (set.next()) {
                    System.out.println("set.getInt(1) = " + set.getInt(1));
                }
            } finally {
                set.close();
            }
        } finally {
            statement.close();
        }