【问题标题】:SimpleJdbcCall for MySql Function yields "Can't set IN parameter for return value of stored function call"用于 MySql 函数的 SimpleJdbcCall 产生“无法为存储的函数调用的返回值设置 IN 参数”
【发布时间】:2019-01-29 05:34:08
【问题描述】:

使用 Spring 文档中的示例,我尝试从 mySQL 函数返回一个值。我不断收到错误Can't set IN parameter for return value of stored function call;

我创建了一个运行良好的 mySQL 函数(在 MySQL Workbench 中运行)。我写了一个SimpleJdbcCall 语句,按照 Spring 文档示例设置了参数,但始终出现此错误。如果我把函数变成一个过程,代码就可以工作,我只需要从结果集中检索返回值。

我使用了https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch13s05.html,第 13.5.8 节作为参考。

CREATE FUNCTION `ScenarioRegistration`(
  environment VARCHAR(45),
  username VARCHAR(15),
  scenario_name VARCHAR(45)) RETURNS int(11)

几个 SELECT 语句后跟一个 INSERT 然后

RETURN scenario_id; // The inserted id

Java 代码:

SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getJdbcTemplate())
 .withFunctionName("ScenarioRegistration")
 .withoutProcedureColumnMetaDataAccess();

simpleJdbcCall.addDeclaredParameter(new SqlParameter("environment"
  ,Types.VARCHAR));

simpleJdbcCall.addDeclaredParameter(new SqlParameter("username" 
  ,Types.VARCHAR));

simpleJdbcCall.addDeclaredParameter(new SqlParameter("scenario_name"
  ,Types.VARCHAR));    

SqlParameterSource parameters = new MapSqlParameterSource()
  .addValue("environment", environment)
  .addValue("username", username)
  .addValue("scenario_name", scenario);

simpleJdbcCall.setReturnValueRequired(true);

Integer scenario_id =  simpleJdbcCall.executeFunction(
   Integer.class, parameters);    

我想要例程做的就是将新插入场景的 id 还给我。 我得到的是: SQL [{? = call scenarioregistration(?, ?)}]; Can't set IN parameter for return value of stored function call.

我觉得有趣的是,它采用了我的三个输入值并将它们更改为一个输出和两个输入值。

谁能告诉我这个问题以及如何解决它?

谢谢,

史蒂文。

【问题讨论】:

    标签: mysql spring spring-jdbc


    【解决方案1】:

    我会参考latest docs here 以获得您的答案。看来 Spring 正在尝试推断输出,因为您没有明确指定一个。

    根据上面的文档,有两种有效的方法可以使用 SimpleJdbcCall 调用所需的函数:

    推断参数

    因为您已经指定了withoutProcedureColumnMetaDataAccess,所以 Spring 不会查看您的函数的输入/输出。如果您想要简单,请不要指定,您应该能够做到:

    SqlParameterSource parameters = new MapSqlParameterSource()
      .addValue("environment", environment)
      .addValue("username", username)
      .addValue("scenario_name", scenario);
    
    Integer scenarioId = new SimpleJdbcCall(getJdbcTemplate())
        .withFunctionName("ScenarioRegistration")
        .executeFunction(Integer.class, parameters);
    

    显式参数

    如果您想保持withoutProcedureColumnMetaDataAccess 处于关闭状态,无论出于何种原因,您都可以这样做:

    Integer scenarioId = new SimpleJdbcCall(getJdbcTemplate)
        .withFunctionName("ScenarioRegistration")
        .withoutProcedureColumnMetaDataAccess()
        .useInParameterNames("environment", "username", "scenario_name")
        .declareParameters(
            new SqlOutParameter("scenario_id", Types.NUMERIC),
            new SqlParameter("environment", Types.VARCHAR),
            new SqlParameter("username", Types.VARCHAR),
            new SqlParameter("scenario_name", Types.VARCHAR)            
        ).executeFunction(Integer.class, parameters);
    

    注意:在此示例中,顺序似乎是关键output 参数应该首先声明,随后命名的IN 参数在最后。即?的参数顺序在[{? = call scenarioregistration(?, ?, ?)}]中是序数)

    替代NamedParameterJdbcTemplate解决方案

    调用函数的另一种方法是通过实际的 JDBC 调用。假设这可以让您免去使用 SimpleJdbcCall 微调的痛苦。

    Integer scenarioId = namedParameterJdbcTemplate.queryForObject(
        "SELECT ScenarioRegistration(:environment, :username, :scenario_name)", 
        parameters, 
        Integer.class);
    

    【讨论】:

    • 谢谢先生。我必须使用 withoutProcedureColumnMetaDataAccess() ,因为没有它,我会收到未授权失败。我的 DBA 告诉我,我们不能假设客户套件会允许访问,所以必须将其关闭。
    • 对不起,我还为时过早。没有解决问题,我仍然遇到同样的错误。
    • 在本地尝试过。声明参数的顺序(显然)很重要!该信息在 Spring 文档中并不清楚。
    • Decided 函数太难实现,耗时太长。我将 RETURN 值转换为 OUT 参数,并将函数转换为存储过程。现在运行良好,感谢您的关注为我解决这个问题。
    • 如果保留 withoutProcedureColumnMetaDataAccess 设置,你在哪里设置要传递给数据库函数的输入参数的值?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多