2015-03-13 67 views
0

我有下面的代码创建StoredProcedure的子类并执行它。我想实现的目标是不止一次地使用新的SQL和新参数的同一个对象。不幸的是,当我设置新的SQL并声明新的参数时,我得到一个异常。不止一次执行StoredProcedure

是否有可能通过“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

你的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

+0

'StoredProcedure'类是抽象类 - 我不能创建它的一个实例。 – ashur 2015-03-13 18:38:14

+0

我添加了一个创建匿名类的例子。但最后,你将不得不为每个过程创建一个新的'StoredProcedure'对象。我不会浪费时间试图找到避免这样做的方法。 – rghome 2015-03-16 09:39:01