2015-03-13 3 views
0

У меня есть следующий код, который создает подкласс StoredProcedure и выполняет его. То, что я хочу достичь, - это использовать один и тот же объект с новыми SQL и новыми параметрами более одного раза. К сожалению, когда я устанавливаю новый SQL и объявляю новые параметры, я получаю исключение.Выполнение хранимой процедуры более одного раза

Как-то возможно «создать» класс для выполнения более одного 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; 
      } 
     } 
    }; 

Если что-то в вашем коде требуется доступ к фактической хранимой процедуре объекту можно обеспечить поглотитель, чтобы разоблачить его.

Также см эту статью: Composition over Inheritance

+0

класс 'StoredProcedure' это абстрактный класс - я не могу создать экземпляр. – ashur

+0

Я добавил пример создания анонимного класса. Но, в конце концов, вам нужно будет создать новый объект 'StoredProcedure' для каждой процедуры. Я бы не тратил время на то, чтобы найти способы избежать этого. – rghome

Смежные вопросы