2

私のアプリケーションには、この形式の関数がいくつかあります。

public long generatedCatId(String name,int age, CallableStatement statement)  throws SQLException
{  
   statement.setString(1,name);  
   statement.setInt(2,age);  
   statement.registerOutParameter(3, Types.NUMERIC);  
   statement.execute();  
   return statement.getLong(3);
}  

私がやりたいのは、Enum許可されたすべてのCallableStatementオブジェクトを含むホワイトリストを作成することです。これにより、列挙型内の値のセットを単純に含むことができます。私が抱えている問題は、CallableStatementオブジェクトなしではオブジェクトを作成できないことConnectionです。この制限を回避する方法はありますか? Statement自動化されたプロセスの一部として 1 日に何十億回も実行されるため、接続オブジェクトを渡したり、繰り返し再コンパイルしたりしたくありません。最後に、ORM ツールは使用しません。

アップデート

私が実行する任意のステートメントの例:

CallableStatement statement = conn.prepareCallable("{Call insert_new_cat(?,?,?)}";
SQL:  insert into cat(id,name,age)  
      values(cat_sequence.nextval,name,age)  
      returning id;
CallableStatement statement = conn.prepareCallable("{Call update_cat(?,?)}";
SQL:  update cat 
      set age = age   
      where id = id;

2 回目の更新

私がしていることについて、いくつかの混乱があるようです。プログラムの流れは次のようになります。

プロセス A は、上記で宣言された関数を呼び出し、コンパイルされたステートメントを提供します。以下の例:

Connection conn = DriverManager.getConnection("foo");  
CallableStatement statement = conn.prepareCall("insert_new_cat");    
for(Cat currentCat : CatList)  
{  
    generateCatId(currentCat.name(),currentCat.age(), statement);  
}  
conn.commit(); 

上記がステートメントの 1 つのコミットと 1 つのコンパイルまたは準備の両方であることに注意してください。そのステートメントを、関数内で比較できる列挙型またはその他の最終的なデータ構造の一部にしたいと考えていgenerateCatIdます。

4

1 に答える 1

3

オブジェクトを無視する方法はありConnectionません。接続プールがある場合を除いて、接続も実際にはそれほど再利用できませんが、プールが再び使用できることを知るには、接続を閉じる必要があります。ただし、をカプセル化する場合は、次のsqlように試すことができます。

enum CallableEnum {
    CALLABLE_ONE("insert_new_cat", 3),
    CALLABLE_TWO("update_cat", 2),
    ;

    private String sql;
    private int parameterCount;

    private CallableEnum(String sql, int params) {
        this.sql = sql;
        this.parameterCount = params;
    }

    public CallableStatement prepare(Connection connection) throws SQLException {
        final StringBuilder builder = new StringBuilder("{CALL ");
        builder.append(this.sql);
        builder.append("(");

        int count = this.parameterCount;
        for (int i = 0; i < count; i++) {
            builder.append("?");
            if (i != count - 1) {
                builder.append(", ");
            }
        }

        return connection.prepareCall(builder.append(")}").toString());
    }
}

そして、次のように使用します。

Connection conn = DriverManager.getConnection("foo");
CallableStatement statement = CallableEnum.CALLABLE_ONE.prepare(conn);
for (Cat currentCat : catList) {
    generateCatId(currentCat.name(), currentCat.age(), statement);
}

conn.commit();
conn.close();

明らかにあなたはあなたのニーズに合うようにそれを修正することができます、これは私があなたの質問から得ることができる唯一のアイデアです:)

アップデート

これはおかしなことに思えます。私はテストしていませんが、すべてをカプセル化するように変更しました。

enum CallableEnum {
    CALLABLE_ONE("insert_new_cat", 3, new Executable<Long>() {
        @Override
        public Long apply(CallableStatement statement, Object... arguments) throws SQLException {
            statement.setString(1, String.valueOf(arguments[0]));
            statement.setInt(2, Integer.parseInt(String.valueOf(arguments[1])));
            statement.registerOutParameter(3, Types.NUMERIC);
            statement.execute();
            return statement.getLong(3);
        }
    }),
    ;

    private String sql;
    private Executable<?> executable;
    private int parameterCount;

    private CallableEnum(String sql, int params, Executable<?> todo) {
        this.sql = sql;
        this.parameterCount = params;
        this.executable = todo;
    }

    public CallableStatement prepare(Connection connection) throws SQLException {
        final StringBuilder builder = new StringBuilder("{CALL ");
        builder.append(this.sql);
        builder.append("(");

        int count = this.parameterCount;
        for (int i = 0; i < count; i++) {
            builder.append("?");
            if (i != count - 1) {
                builder.append(", ");
            }
        }

        return connection.prepareCall(builder.append(")}").toString());
    }

    public <T> T execute(Connection conn, Object... arguments) throws SQLException {
        CallableStatement st = this.prepare(conn);
        return (T) this.executable.apply(st, arguments);
    }

    private interface Executable<T> {
        T apply(CallableStatement st, Object... arguments) throws SQLException;
    }
}

これで、次のように使用できます。

Connection conn = DriverManager.getConnection("foo");
for (Cat currentCat : catList) {
    CallableEnum.CALLABLE_ONE.execute(conn, currentCat.name(), currentCat.age());
}
conn.commit();
conn.close();

これがあなたが望んでいたものなのか、それともうまくいくのかはわかりませんが、私はあなたにそれを残します:)

于 2012-08-16T13:59:29.607 に答える