SimpleJdbcCall时对MySQL的函数产生“无法在参数存储函数调用的返回值”

时间:2019-01-29 05:34:08

标签: mysql spring spring-jdbc

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

我创建一个MySQL函数(在MySQL工作台RAN)工作正常。我写了一个SimpleJdbcCall语句,按照Spring docs示例设置了参数,但是始终出现此错误。如果将函数转换为过程,则代码可以正常工作,我只需要从结果集中检索返回值即可。

我用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.

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

任何人指教我的问题,以及如何解决它?

谢谢

史蒂芬。

1 个答案:

答案 0 :(得分:2)

对于您的答案,我会参考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);