Весняний шаблон JDBC для виклику збережених процедур


78

Який правильний спосіб викликати збережені процедури за допомогою сучасного шаблону JDBC Spring (circa 2012)?

Скажімо, у мене є збережена процедура, яка оголошує INі OUTпараметри, і приблизно таке:

mypkg.doSomething(
    id OUT int,
    name IN String,
    date IN Date
)

Я натрапила на CallableStatementCreatorоснові підходів , де ми повинні явним чином зареєструвати INі OUTпараметри. Розглянемо наступний метод у JdbcTemplateкласі:

public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters)

Звичайно, я знаю, що можу використовувати його так:

List<SqlParameter> declaredParameters = new ArrayList<SqlParameter>();

declaredParameters.add(new SqlOutParameter("id", Types.INTEGER));
declaredParameters.add(new SqlParameter("name", Types.VARCHAR));
declaredParameters.add(new SqlParameter("date", Types.DATE));

this.jdbcTemplate.call(new CallableStatementCreator() {

    @Override
    CallableStatement createCallableStatement(Connection con) throws SQLException {
        CallableStatement stmnt = con.createCall("{mypkg.doSomething(?, ?, ?)}");

        stmnt.registerOutParameter("id", Types.INTEGER);
        stmnt.setString("name", "<name>");
        stmnt.setDate("date", <date>);

        return stmnt;
    }
}, declaredParameters);

Яка мета, declaredParametersколи я вже реєструю їх у своїй cscреалізації? Іншими словами, чому мені потрібно здавати acsc коли весна може просто робити con.prepareCall(sql)всередині? В основному, чи не можу я пройти в жоден з них замість обох?

Або є набагато кращий спосіб викликати збережені процедури (за допомогою Spring JDBC Template), ніж той, з яким я стикався до цього часу?

Примітка: Ви можете знайти багато питань, які, схоже, мають подібний заголовок, але вони не збігаються з цим.


3
Я бачу, що це питання зараз досить популярне, і вже пройшло більше 2 років з того моменту, як його задали. Якщо хтось вважає, що є ще більш приємний спосіб викликати збережені процедури, коли Spring 4 вийшов, надішліть відповідь або запропонуйте редагувати.
adarshr

Відповіді:


94

Навесні існує кілька способів викликати збережені процедури.

Якщо ви використовуєте CallableStatementCreatorдля оголошення параметрів, ви будете використовувати стандартний інтерфейс Java CallableStatement, тобто реєструйте параметри та встановлюйте їх окремо. Використання SqlParameterабстракції зробить ваш код чистішим.

Рекомендую вам подивитися SimpleJdbcCall. Його можна використовувати так:

SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
    .withSchemaName(schema)
    .withCatalogName(package)
    .withProcedureName(procedure)();
...
jdbcCall.addDeclaredParameter(new SqlParameter(paramName, OracleTypes.NUMBER));
...
jdbcCall.execute(callParams);

Для простих процедур ви можете використовувати метод jdbcTemplate' update:

jdbcTemplate.update("call SOME_PROC (?, ?)", param1, param2);

SimpleJdbcCallздається справді крутим. Я протестую це і повідомлю вам, як це було в моєму випадку.
adarshr

2
Метод оновлення у мене не спрацював, я отримав поганий виняток з граматики SQL, навіть незважаючи на те, що моя заява виконана в базі даних чудово SimpleJdbcCall працював дуже добре
otgw

Я намагаюся використовувати jdbcTemplate.update () так само, як ви сказали, але отримую помилку "cannot invoke update on null object".
хан Сулеман

1
@EpicPandaForce у мене був NamedParameterJdbcTemplate, а не JdbcTemplate
Алекс

8
Я не знаю, чи це специфічний для Oracle синтаксис, але синтаксис для Oracle такий: jdbcTemplate.update("{ call my_schema.my_pkg.SOME_PROC (?, ?) }", param1, param2);(зверніть увагу на фігурні дужки).
inanutshellus

50

Ось способи виклику збережених процедур з Java

1. Використання CallableStatement:

 connection = jdbcTemplate.getDataSource().getConnection();
  CallableStatement callableStatement = connection.prepareCall("{call STORED_PROCEDURE_NAME(?, ?, ?)}");
  callableStatement.setString(1, "FirstName");
  callableStatement.setString(2, " LastName");
  callableStatement.registerOutParameter(3, Types.VARCHAR);
  callableStatement.executeUpdate();

Тут ми зовні керуємо закриттям ресурсу

2. Використання CallableStatementCreator

 List paramList = new ArrayList();
    paramList.add(new SqlParameter(Types.VARCHAR));
    paramList.add(new SqlParameter(Types.VARCHAR));
    paramList.add(new SqlOutParameter("msg", Types.VARCHAR));

    Map<String, Object> resultMap = jdbcTemplate.call(new CallableStatementCreator() {

    @Override
    public CallableStatement createCallableStatement(Connection connection)
    throws SQLException {

    CallableStatement callableStatement = connection.prepareCall("{call STORED_PROCEDURE_NAME(?, ?, ?)}");
    callableStatement.setString(1, "FirstName");
            callableStatement.setString(2, " LastName");
            callableStatement.registerOutParameter(3, Types.VARCHAR);
    return callableStatement;

    }
    }, paramList);

3. Використовуйте SimpleJdbcCall:

SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)

.withProcedureName("STORED_PROCEDURE_NAME");

Map<String, Object> inParamMap = new HashMap<String, Object>();
inParamMap.put("firstName", "FirstNameValue");
inParamMap.put("lastName", "LastNameValue");
SqlParameterSource in = new MapSqlParameterSource(inParamMap);


Map<String, Object> simpleJdbcCallResult = simpleJdbcCall.execute(in);
System.out.println(simpleJdbcCallResult);

4. Використовуйте StoredProcedure клас org.springframework.jdbc.object

The Code:
First Create subclass of StoredProcedure: MyStoredProcedure

class MyStoredProcedure extends StoredProcedure {

public MyStoredProcedure(JdbcTemplate jdbcTemplate, String name) {

super(jdbcTemplate, name);
setFunction(false);

}

}

Use MyStoredProcedure to call database stored procedure:


//Pass jdbcTemlate and name of the stored Procedure.
MyStoredProcedure myStoredProcedure = new MyStoredProcedure(jdbcTemplate, "PROC_TEST");

//Sql parameter mapping
SqlParameter fNameParam = new SqlParameter("fName", Types.VARCHAR);
SqlParameter lNameParam = new SqlParameter("lName", Types.VARCHAR);
SqlOutParameter msgParam = new SqlOutParameter("msg", Types.VARCHAR);
SqlParameter[] paramArray = {fNameParam, lNameParam, msgParam};


myStoredProcedure.setParameters(paramArray);
myStoredProcedure.compile();


//Call stored procedure
Map storedProcResult = myStoredProcedure.execute("FirstNameValue", " LastNameValue");

Довідково


Як би це виглядало, якби я мав процедуру повернення у кілька рядків? Це буде список об'єктів <String, Object> Map?
Kent Bull,

1
@Kent - Ви маєте рацію. Це буде List <Map <String, Object >> для декількох рядків.
Сайрам Кукадала,

Простий JDBC (варіант 1.) видається найпростішим варіантом у цьому контексті -> +1
бомбардувальник Marmite

19

Я зазвичай вважаю за краще розширювати StoredProcedureклас на основі Spring для виконання збережених процедур.

  1. Вам потрібно створити свій конструктор класів і в ньому потрібно викликати StoredProcedureконструктор класу. Цей конструктор суперкласу приймає DataSource та ім'я процедури.

    Приклад коду:

    public class ProcedureExecutor extends StoredProcedure {
          public ProcedureExecutor(DataSource ds, String funcNameorSPName) {
            super(ds, funcNameorSPName);
            declareParameter(new SqlOutParameter("v_Return", Types.VARCHAR, null, new SqlReturnType() {
                    public Object getTypeValue(CallableStatement cs,
                         int paramIndex, int sqlType, String typeName) throws SQLException {
                    final String str = cs.getString(paramIndex);
                    return str;
                }           
            }));    
            declareParameter(new SqlParameter("your parameter",
                    Types.VARCHAR));
            //set below param true if you want to call database function 
            setFunction(true);
            compile();
            }
    
  2. Перевизначити метод виконання збереженого виклику процедури, як показано нижче

    public Map<String, Object> execute(String someParams) {
                 final Map<String, Object> inParams = new HashMap<String, Object>(8);
                 inParams.put("my param", "some value");
                 Map outMap = execute(inParams);
                 System.out.println("outMap:" + outMap);
                 return outMap;
             }
    

Сподіваюся, це вам допоможе.


1

Ще один спосіб викликати збережену процедуру:

sql="execute Procedure_Name ?";
Object search[]={Id};
List<ClientInvestigateDTO> client=jdbcTemplateObject.query(sql,search,new 
   ClientInvestigateMapper());

У цьому прикладі 'ClientInvestigateDTO' - це клас POJO, а 'ClientInvestigateMapper' - клас mapper.'Client 'зберігає весь результат, який ви отримуєте при виклику збереженої процедури.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.