我正在構建一個應用程序(使用spring-integration),它應該從任何入站網關接收Request對象並調用MS SQL存儲過程。 請求對象包含String
屬性procedureName
和List<Pair<String, Object>>
屬性parameters
。問題是,我無法找到一個解決方案,當我不知道它是編譯時的長度時如何傳遞參數列表。 配置出站網關:stored-proc-outbound-gateway中的參數個數不定
<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個參數,他們的名字是「第一」和「第二」,我將配置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)
我debuged通ListSqlParameterSourceFactory和它的工作如預期,一個SqlParameterSource是
[0] = {[email protected]}"@Currency" -> "R"
[1] = {[email protected]}"@LegalGroupList" -> "(ALL)"
[2] = {[email protected]}"@FilterForAny" -> ""
[3] = {[email protected]}"@ShowCloseExpiration" -> "0"
[4] = {[email protected]}"@IsNewMethodology" -> "0"
[5] = {[email protected]}"@CloseExpirationDays" -> "0"
[6] = {[email protected]}"@WhatIfDealFilter" -> "R"
[7] = {[email protected]}"@UtilizationType" -> "A"
[8] = {[email protected]}"@BookDate" -> "20141202 00:00:00.000"
[9] = {[email protected]}"@Transliteration" -> "0"
[10] = {[email protected]}"@PartyGroupList" -> "(ALL)"
[11] = {[email protected]}"@RiskZone" -> "L"
[12] = {[email protected]}"@HideLESublimits" -> "0"
有什麼我錯過了嗎?
UPD2: 彈簧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.
從程序名和@
,現在可以正確地裝入列的元數據和綁定變量。這並不意味着我的申請有效,但至少我可以走得更遠。阿爾喬姆的建議幫助解決了主要問題。
嘗試這樣做,但它不仍然工作。你能否看看更新後的帖子? – 2014-12-04 15:39:21
我明白了。你真的錯過了參數的順序。 '@ BookDate'是程序規範中的第一個。但是在你的'SqlParameterSource'中,它位於'[8]'位置。 – 2014-12-04 15:57:51
Artem,但是如果我們深入'MapSqlParameterSource'內部,我們會看到它將參數保存在沒有排序的通常'HashMap'中。來自javadocs:_This類用於將簡單的參數值Map傳遞給NamedParameterJdbcTemplate類的方法。因此,我期望Spring將通過名稱綁定參數。實際上,我按照正確的順序傳遞參數,HashMap完成所有的混亂 – 2014-12-05 08:03:58