Java - 使用泛型参数调用存储过程

时间:2012-06-21 13:48:49

标签: java sql oracle generics

我想调用存储过程(Oracle)。因为我的过程调用是动态的,我需要动态管理过程参数。 问题是我想避免使用instanceof关键字,因为它不适用于主要类型。 是否有更简洁的方法来调用此类程序?

    public void executeProcedure(StoredProcedure proc) {        
        LinkedList<ProcedureParameter<?>> parameters = proc.getParameters();

        CallableStatement statement = connection.prepareCall("{ call MY_PACKAGE.MY_PROCEDURE( ?, ?, ? ) }");

        for (int i = 0; i < parameters.size(); i++) {
            Object paramValue = parameters.get(i).getValue();

            // Beginning of smelly code

            if (paramValue instanceof String) {
                statement.setString(i + 1, (String) paramValue);
            }
            else if (paramValue instanceof ...) {
                ...
            }
            else {
                ...
            }

            // End of smelly code
        }

        statement.execute();            
    }

    public class ProcedureParameter<E> {
        private String name;
        private E value;

        public ProcedureParameter(String name) {
            this.name = name;
        }

        public ProcedureParameter(String name, E value) {
            this.name = name;
            this.value = value;
        }

        // Getters and setters
    }

谢谢你的任何想法。

3 个答案:

答案 0 :(得分:1)

我认为它可以帮助您在没有instanceof http://en.wikipedia.org/wiki/Visitor_pattern

的情况下实现所需的功能

答案 1 :(得分:1)

你可以使用反射,虽然这不是好习惯,因为它较慢并且阻止编译器检查以确保方法调用是正确的。您可以将每个类映射到其对应的CallableStatement方法。例如,String将映射到“setString”。

List<ProcedureParameter<?>> parameters = proc.getParameters();
CallableStatement statement = connection.prepareCall("{ call MY_PACKAGE.MY_PROCEDURE( ?, ?, ? ) }");

Map<Class<?>, String> methods = new HashMap<Class<?>, String>();
methods.put(String.class, "setString");
//...

for (int i = 0; i < parameters.size(); i++) {
  Object paramValue = parameters.get(i).getValue();
  Class<?> paramValueClass = paramValue.getClass();
  String stmtMethod = methods.get(paramValueClass);
  if (stmtMethod != null){
    Method method = statement.getClass().getMethod(stmtMethod, int.class, paramValueClass);
    method.invoke(statement, i+1, paramValue);
  } else {
    //error
  }
}

答案 2 :(得分:1)

我会实施另一个解决方案,这可能不是最好的解决方案,但在我看来,不是很臭。

由于StoredProcedure是一个接口,每个存储过程都实现此接口。因此,每个实现都将包含一个返回call ...语句的方法,因为开发人员知道他实现的过程所需的参数类型。