stored-proc-outbound-gateway中的参数数量不一致

时间:2014-12-04 10:23:16

标签: java spring spring-integration spring-jdbc

我正在构建一个应用程序(使用spring-integration),它应该从whatever-inbound-gateway接收Request对象并调用MS SQL存储过程。 Request对象包含String属性procedureNameList<Pair<String, Object>>属性parameters。问题是我无法找到解决方案,当我在编译时不知道它的长度时,如何传递参数列表。 配置出站网关:

<int-jdbc:stored-proc-outbound-gateway
        id="outbound-gateway-procedure" request-channel="requestChannel"
        data-source="dataSource" stored-procedure-name-expression="payload.procedureName"
        sql-parameter-source-factory="someParameterSourceFactory" >

</int-jdbc:stored-proc-outbound-gateway>

如果我知道列表中只有2个参数,而且他们的名字是“第一个&#39;和&#39;秒&#39;,我会像这样配置sql-parameter-source-factory

<bean id="someParameterSourceFactory" class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
    <property name="parameterExpressions">
        <map>
            <entry key="first" value-type="java.lang.String" value="payload.parameters.get(1).second"/>
            <entry key="second" value-type="java.lang.String" value="payload.parameters.get(2).second"/>
        </map>
    </property>
</bean>

但是我不知道在编译时参数的数量都没有。有什么建议吗?

UPD: 存储过程如下所示:

create procedure [dbo].[pnzLimitUtilization_Show]
(
     @BookDate          datetime      
   , @LegalGroupList    varchar(4000)  
   , @Currency          char(3) 
   , @FilterForAny      nvarchar(255) = '' 
   , @RiskZone          char(1)      = 'A'
   , @WithZerroExposure char(1)      = '0'  
   , @Transliteration   bit          = 0 
   , @IsNewMethodology  bit          = 0       
   , @UtilizationType   char(1)      = 'A'
   , @PartyGroupList    varchar(255) = NULL             
   , @HostName          varchar(255) = NULL           
   , @ShowCloseExpiration bit = 0 
   , @CloseExpirationDays int = 90 
   , @WhatIfDealFilter   char(1)         = 'R'               
   , @HideLESublimits   bit          = 0
)
as begin ....

新配置:

<int-jdbc:stored-proc-outbound-gateway
        id="outbound-gateway-procedure" request-channel="requestChannel"
        data-source="dataSource" stored-procedure-name-expression="payload.name.toString()"
        ignore-column-meta-data="true"
        sql-parameter-source-factory="listParameterSourceFactory"
        reply-channel="replyChannel">
</int-jdbc:stored-proc-outbound-gateway>

<bean id="listParameterSourceFactory" class="my.pack.integration.ListSqlParameterSourceFactory" />

ListSqlParameterSourceFactory:

public class ListSqlParameterSourceFactory implements SqlParameterSourceFactory {

    @Override
    @SuppressWarnings("unchecked")
    public SqlParameterSource createParameterSource(Object input) {
        GetSourceDataRequest message = (GetSourceDataRequest) input;
        List<NamedValueEntity> params = message.getParameters();
        MapSqlParameterSource source = new MapSqlParameterSource();
        for (NamedValueEntity param : params) {
            source.addValue(param.getName().toString(), param.getValue());
        }
        return source;
    }
}

现在我收到错误

Caused by: org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call dbo.pnzLimitUtilization_Show()}]; nested exception is java.sql.SQLException: Procedure or function 'pnzLimitUtilization_Show' expects parameter '@BookDate', which was not supplied.
    at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:97)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

我通过ListSqlParameterSourceFactory进行了调试,它按预期工作,SqlParameterSource是

[0] = {java.util.HashMap$Entry@4243}"@Currency" -> "R"
[1] = {java.util.HashMap$Entry@4246}"@LegalGroupList" -> "( ALL )"
[2] = {java.util.HashMap$Entry@4249}"@FilterForAny" -> ""
[3] = {java.util.HashMap$Entry@4252}"@ShowCloseExpiration" -> "0"
[4] = {java.util.HashMap$Entry@4255}"@IsNewMethodology" -> "0"
[5] = {java.util.HashMap$Entry@4258}"@CloseExpirationDays" -> "0"
[6] = {java.util.HashMap$Entry@4261}"@WhatIfDealFilter" -> "R"
[7] = {java.util.HashMap$Entry@4264}"@UtilizationType" -> "A"
[8] = {java.util.HashMap$Entry@4267}"@BookDate" -> "20141202 00:00:00.000"
[9] = {java.util.HashMap$Entry@4270}"@Transliteration" -> "0"
[10] = {java.util.HashMap$Entry@4273}"@PartyGroupList" -> "( ALL )"
[11] = {java.util.HashMap$Entry@4276}"@RiskZone" -> "L"
[12] = {java.util.HashMap$Entry@4279}"@HideLESublimits" -> "0"

我错过了什么吗?

UPD2: Spring-jdbc日志:

05 dec 2014 14:15:28 DEBUG SimpleJdbcCall - Compiled stored procedure. Call string is [{call dbo.pnzLimitUtilization_Show()}]
05 dec 2014 14:15:28 DEBUG SimpleJdbcCall - SqlCall for procedure [dbo.pnzLimitUtilization_Show] compiled
05 dec 2014 14:15:28 DEBUG CallMetaDataContext - Matching [@FilterForAny, @BookDate, @Currency, @UtilizationType, @HideLESublimits, @ShowCloseExpiration, @Transliteration, @IsNewMethodology, @RiskZone, @WhatIfDealFilter, @CloseExpirationDays, @PartyGroupList, @LegalGroupList] with []
05 dec 2014 14:15:28 DEBUG CallMetaDataContext - Found match for []
05 dec 2014 14:15:28 DEBUG SimpleJdbcCall - The following parameters are used for call {call dbo.pnzLimitUtilization_Show()} with: {}
05 dec 2014 14:15:28 DEBUG JdbcTemplate - Calling stored procedure [{call dbo.pnzLimitUtilization_Show()}]

看起来它没有传递任何参数.. 调试CallMetaDataContext我发现this.callParameters为空。它与ignore-column-meta-data="true"没有联系吗?但如果我将其切换到false,我会看到另一个错误:

05 dec 2014 14:41:33 DEBUG CallMetaDataProviderFactory - Using org.springframework.jdbc.core.metadata.SqlServerCallMetaDataProvider
05 dec 2014 14:41:33 DEBUG CallMetaDataProvider - Retrieving metadata for null/null/dbo.pnzLimitUtilization_Show
05 dec 2014 14:41:36 DEBUG DataSourceUtils - Returning JDBC Connection to DataSource
org.springframework.messaging.MessageHandlingException: error occurred in message handler [org.springframework.integration.jdbc.StoredProcOutboundGateway#0]; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Unable to determine the correct call signature for dbo.pnzLimitUtilization_Show - package name should be specified separately using '.withCatalogName("dbo")'

UPD3: 好的,我从过程名称中删除了dbo.,从参数名称中删除了@,现在它正确地加载了列元数据并绑定了变量。这并不意味着我的应用程序有效,但至少我可以更进一步。 Artem的建议有助于解决主要问题。

1 个答案:

答案 0 :(得分:1)

首先,您的PROCEDURE看起来如何?至少是规范。

为什么您确定任何参数列表对于您的过程调用是合法的?

从另一方面来说,您可以使用SqlParameterSourceFactory自定义,但它确实应该完全自定义实现。这样的话,因为你说你的payloadparameters属性:

public class PairSqlParameterSourceFactory implements SqlParameterSourceFactory {


    public SqlParameterSource createParameterSource(Object input) {
        Message<Request> message = (Message<Request>) input;
        List<Pair<String, Object>> pairs = message.getPayload().getParameters();
        MapSqlParameterSource source = new MapSqlParameterSource();
        for (Pair<String, Object> pair : pairs) { 
            source.addValue(pair.getName(), pair.getValue());
        }
        return source;
    }

}