我的应用程序中有几个这种形式的函数:
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调用上面声明的函数,提供编译的Statement。示例如下:
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
函数中进行比较。
答案 0 :(得分: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();
我不知道这是否是你想要的,或者即使它会起作用,但我会留下你的意思:)