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重复重新编译,因为这将作为自动化过程的一部分每天运行数十亿次。最后,我不会使用任何 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;

第二次更新

我在做什么似乎有些混乱。程序的流程是这样的:

进程 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(); 

请注意以上内容如何既是一次提交,又是一次编译或准备语句。我希望该语句成为枚举或其他最终数据结构的一部分,然后我可以在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 回答