多次执行存储过程

时间:2015-03-13 13:30:57

标签: java spring oracle function

我有以下代码创建StoredProcedure的子类并执行它。我想要实现的是将同一个对象与新SQL和新参数一起使用多次。不幸的是,当我设置新的SQL并声明新的参数时,我得到了一个异常。

在某种程度上可以" generify"用新参数执行多个SQL的类? 在我的特定示例中有多个问题

代码

package procedures;

import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.StoredProcedure;

import javax.sql.DataSource;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

public class MyProcedure extends StoredProcedure {

    private static String SQL = "hr.get_size";

    public MyProcedure(DataSource dataSource) {
        super(dataSource, SQL);
        declareParameter(new SqlOutParameter("param_out", Types.NUMERIC));
        declareParameter(new SqlParameter("param_in", Types.VARCHAR));
        setFunction(true);
        compile();
    }

    public Object execute(String tableName) {
        Map in = new HashMap();
        in.put("param_in", tableName);
        Map out = execute(in);
        if (!out.isEmpty()) {
            return out.get("param_out");
        } else {
            return null;
        }
    }
}

引发异常的电话:

public static void main(String[] args) {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    MyProcedure myProcedure = applicationContext.getBean(MyProcedure.class);
    System.out.println(myProcedure.execute("employees"));

    myProcedure.setSql("hr.get_all_tables");
    myProcedure.declareParameter(new SqlOutParameter("param_out", Types.VARCHAR));
    myProcedure.setFunction(true);
    myProcedure.compile();
    System.out.println(myProcedure.execute());
}

例外:

Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: Cannot add parameters once the query is compiled
    at org.springframework.jdbc.object.RdbmsOperation.declareParameter(RdbmsOperation.java:278)
    at org.springframework.jdbc.object.StoredProcedure.declareParameter(StoredProcedure.java:99)
    at main.Main.main(Main.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

1 个答案:

答案 0 :(得分:2)

您的MyProcedure课程不应该延长StoredProcedure,而是委托给它。

我认为你所做的是滥用类扩展的一个例子。如果你的子类要尊重超类的行为,你应该只扩展一个类或接口(参见Liskov Substitution Principal)。 StoredProcedure类封装了一个过程并且是只读的,它为使用它的类提供了某些保证。你的班级可以在后台更改程序和参数,所以这是另一回事。

您应该让StoredProcedure成为您班级的私人成员并委托对其进行调用(请参阅Delegation Pattern)。

当您需要访问新的存储过程时,您只需丢弃旧的StoredProcedure对象和new另一个对象。如果需要,您可以创建一个匿名内部类:

    StoredProcedure sp = new StoredProcedure(ds, SQL) {
        public Object execute(String tableName) {
            Map in = new HashMap();
            in.put("param_in", tableName);
            Map out = execute(in);
            if (!out.isEmpty()) {
                return out.get("param_out");
            } else {
                return null;
            }
        }
    };

如果代码中的某些内容需要访问实际的存储过程对象,则可以提供一个getter来公开它。

另见本文:Composition over Inheritance