用于调用存储过程的Spring JDBC模板

时间:2012-02-20 12:59:55

标签: java spring spring-jdbc jdbctemplate

使用现代(大约2012年)Spring JDBC模板调用存储过程的正确方法是什么?

说,我有一个声明INOUT参数的存储过程,如下所示:

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

我遇到了基于CallableStatementCreator的方法,我们必须明确注册INOUT参数。请考虑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实施中注册时,目的是什么?换句话说,当春天只能在内部csc时,为什么我需要传递con.prepareCall(sql)?基本上,我不能传递其中任何一个而不是两个吗?

或者,有没有比我目前遇到的更好的方法来调用存储过程(使用Spring JDBC Template)?

注意:您可能会发现许多似乎具有类似标题的问题,但它们与此问题不同。

4 个答案:

答案 0 :(得分:83)

有许多方法可以在Spring中调用存储过程。

如果使用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的{​​{1}}方法:

update

答案 1 :(得分:26)

以下是从java

调用存储过程的方法

<强> 1。使用CallableStatement:

        // Here you have it - a queue of arrays
        // Really, it's no different than a queue of any other type
        Queue<int[]> queue = new Queue<int[]>(
            // Construct the queue from the following array of arrays
            new[]
            {
                new[] { 3, 2, 1, 0 },
                new[] { 32, 24, 234, 3 }
                // Whatever you want
            }
        );

        // If all you want is a queue with four ints, why bother with the queue of array thing?
        // You can initialize a queue with some numbers like this
        Queue<int> queueOfInts = new Queue<int>(new[] { 3, 2, 1, 0 });

我们在外部管理资源关闭

<强> 2。使用CallableStatementCreator

 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();

第3。使用SimpleJdbcCall:

 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);

<强> 4。使用org.springframework.jdbc.object的StoredProcedure类

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);

Reference

答案 2 :(得分:17)

我通常更喜欢扩展基于Spring的StoredProcedure类来执行存储过程。

  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;
             }
    
  3. 希望这会对你有所帮助。

答案 3 :(得分:1)

调用存储过程的另一种方法是:

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

在此示例中,“ClientInvestigateDTO”是POJO类,“ClientInvestigateMapper”是映射器类。“客户端”存储调用存储过程时获得的所有结果。