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

发布于 2025-01-07 02:46:08 字数 1559 浏览 0 评论 0原文

使用现代(大约 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 实施?换句话说,当 spring 可以简单地在内部执行 con.prepareCall(sql) 时,为什么我需要传入 csc 呢?基本上,我不能传递其中之一而不是两者吗?

或者,是否有比我迄今为止遇到的更好的方法来调用存储过程(使用 Spring JDBC 模板)?

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

What is the correct way to invoke stored procedures using modern day (circa 2012) Spring JDBC Template?

Say, I have a stored procedure that declares both IN and OUT parameters, something like this:

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

I have come across CallableStatementCreator based approaches where we have to explicitly register IN and OUT parameters. Consider the following method in JdbcTemplate class:

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

Of course, I do know that I can use it like so:

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

What is the purpose of declaredParameters when I am already registering them in my csc implementation? In other words, why would I need to pass in a csc when spring can simply do con.prepareCall(sql) internally? Basically, can't I pass in either one of them instead of both of them?

Or, is there a much better way to call stored procedures (using Spring JDBC Template) than what I have come across so far?

Note: You may find many questions that appear to have a similar title but they are not the same as this one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

好多鱼好多余 2025-01-14 02:46:08

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

对于简单的过程,您可以使用jdbcTemplateupdate方法:

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

There are a number of ways to call stored procedures in Spring.

If you use CallableStatementCreator to declare parameters, you will be using Java's standard interface of CallableStatement, i.e register out parameters and set them separately. Using SqlParameter abstraction will make your code cleaner.

I recommend you looking at SimpleJdbcCall. It may be used like this:

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

For simple procedures you may use jdbcTemplate's update method:

jdbcTemplate.update("call SOME_PROC (?, ?)", param1, param2);
紫﹏色ふ单纯 2025-01-14 02:46:08

以下是从 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.使用org.springframework.jdbc.object的StoredProcedure类

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

参考

Here are the ways to call the stored procedures from java

1. Using 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();

Here we externally manage the resource closing

2. Using 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. Use 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. Use StoredProcedure class of 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");

Reference

无畏 2025-01-14 02:46:08

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

  1. 您需要创建类构造函数,并需要在其中调用StoredProcedure类构造函数。这个超类构造函数接受数据源和过程名称。

    示例代码:

    public class procedureExecutor 扩展 StoredProcedure {
          公共ProcedureExecutor(数据源ds,字符串funcNameorSPName){
            super(ds, funcName 或 SPName);
            declareParameter(new SqlOutParameter("v_Return", Types.VARCHAR, null, new SqlReturnType() {
                    公共对象 getTypeValue(CallableStatement cs,
                         int paramIndex, int sqlType, String typeName) 抛出 SQLException {
                    最终字符串 str = cs.getString(paramIndex);
                    返回字符串;
                }           
            }));    
            declareParameter(new SqlParameter("你的参数",
                    类型.VARCHAR));
            //如果要调用数据库函数,则将下面的参数设置为 true 
            设置函数(真);
            编译();
            }
    
  2. 重写存储过程调用的执行方法如下

    public Map<字符串,对象>执行(字符串一些参数){
                 最终 Map inParams = new HashMap(8);
                 inParams.put("我的参数", "某个值");
                 映射 outMap = 执行(inParams);
                 System.out.println("outMap:" + outMap);
                 返回outMap;
             }
    

希望这对您有帮助。

I generally prefer to extend Spring based StoredProcedure class to execute stored procedures.

  1. You need to create your class constructor and need to call StoredProcedure class constructor in it. This super class constructor accepts DataSource and procedure name.

    Example code:

    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. Override execute method of stored procedure call as below

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

Hope this helps you.

许你一世情深 2025-01-14 02:46:08

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

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

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

One more way to call stored procedure is:

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

In this example 'ClientInvestigateDTO' is the POJO class and 'ClientInvestigateMapper' is the mapper class.'client' stores all the result you get on calling the stored procedure.

悸初 2025-01-14 02:46:08

在某些情况下,使用jdbcTemplate.query()调用过程不会捕获该过程引发的错误。我在 MS SqlServer 上看到过这种行为,其中一个过程使用以下命令引发错误
RAISEERROR 如果发生错误并使用查询方法调用过程会忽略错误。

我切换到 SimpleJdbcTemplate 进行过程调用并且有效。
注意:这可能不适用于程序。就我而言,过程正在执行选择以返回数据,之后如果没有找到任何数据,则会引发错误。使用 jdbcTemplate.query 会给我返回一个没有错误的空数据集。

Using jdbcTemplate.query() to call a procedure does not catch errors raised by the procedure in some cases. I have seen this behavior on MS SqlServer where a proceudure was raising an error using
RAISEERROR in case of an error and calling the proc using the query method was ignoring the error.

I switched to SimpleJdbcTemplate for procedure calls and that works.
Note : this might not apply to procedures. In my case the proc was doing a select to return data and after that if it had not found any data it would raise an error. Using jdbcTemplate.query woudld give me back an empty data set with no error.

土豪我们做朋友吧 2025-01-14 02:46:08

我正在回复您的评论:

或者,是否有比我迄今为止遇到的更好的方法来调用存储过程(使用 Spring JDBC 模板)?

还有评论区的一条评论:

如果有人认为 Spring 4 已经发布,还有更好的方法来调用存储过程

如果您愿意使用第三方库,jOOQ 有一个代码生成器,可用于为所有存储的文件生成存根过程、函数、包、UDT 等。

在您的特定情况下,将有一个 Mypkg 类,其中包含一个 doSomething() 方法,您可以像这样调用这:

int id = Mypkg.doSomething(
    configuration, // This wraps your JDBC connection
    name, date
);

就是这样。所有到 JDBC 的管道都得到处理,当您拥有 UDT(Oracle OBJECTTABLE 类型、PACKAGE 类型)时,这尤其好,或 隐式游标

您说您想使用 Spring JDBC 模板,但显然您可以从中提取 JDBC Connection 并将其提供给 jOOQ,因此从技术上讲,您仍将使用 Spring JDBC 模板。 ..

免责声明:我在 jOOQ 背后的公司工作

I'm replying to your comment:

Or, is there a much better way to call stored procedures (using Spring JDBC Template) than what I have come across so far?

And to a comment from the comment section:

If anyone thinks there is an even nicer way to call stored procedures now that Spring 4 is out

If you're open to using a third party library, jOOQ has a code generator that can be used to generate stubs for all of your stored procedures, functions, packages, UDTs, etc.

In your particular case, there would be a Mypkg class with a doSomething() method that you could call like this:

int id = Mypkg.doSomething(
    configuration, // This wraps your JDBC connection
    name, date
);

That's it. All the plumbing to JDBC is being taken care of, which is especially nice when you have UDTs (Oracle OBJECT or TABLE types, PACKAGE types), or implicit cursors.

You said that you'd like to use Spring JDBC Template, but you can obviously just extract the JDBC Connection from it and supply that to jOOQ, so technically, you'll still be using Spring JDBC Template...

Disclaimer: I work for the company behind jOOQ

挽你眉间 2025-01-14 02:46:08

如果是 DML 程序&我使用的没有返回变量:

Map params = ImmutableMap.builder().put("p1", p1).put("p2", p2).build();
jdbcTemplate.update("{ call pack.proc( :p1, :p1) }", params);

PS 如果有返回变量,最好使用函数

In case of DML procedure & no return variables I used:

Map params = ImmutableMap.builder().put("p1", p1).put("p2", p2).build();
jdbcTemplate.update("{ call pack.proc( :p1, :p1) }", params);

PS In case there are return variables better use functions instead

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文