儲存過程
在某些情況下,普通的 JDBC 支援是不夠的。也許您需要處理遺留的關係資料庫模式,或者您有複雜的資料處理需求,但最終,您必須使用儲存過程或儲存函式。自 Spring Integration 2.1 以來,我們提供了三個元件來執行儲存過程或儲存函式
-
儲存過程入站通道介面卡
-
儲存過程出站通道介面卡
-
儲存過程出站閘道器
支援的資料庫
為了啟用對儲存過程和儲存函式的呼叫,儲存過程元件使用org.springframework.jdbc.core.simple.SimpleJdbcCall類。因此,以下資料庫完全支援執行儲存過程
-
Apache Derby
-
DB2
-
MySQL
-
Microsoft SQL Server
-
Oracle
-
PostgreSQL
-
Sybase
如果您想執行儲存函式,則以下資料庫完全支援
-
MySQL
-
Microsoft SQL Server
-
Oracle
-
PostgreSQL
|
儘管您的特定資料庫可能不完全受支援,但您很可能仍然可以成功使用儲存過程 Spring Integration 元件,前提是您的 RDBMS 支援儲存過程或儲存函式。 事實上,一些提供的整合測試使用了H2 資料庫。儘管如此,徹底測試這些使用場景仍然非常重要。 |
通用配置屬性
所有儲存過程元件共享某些配置引數
-
auto-startup:生命週期屬性,指示此元件是否應在應用程式上下文啟動期間啟動。預設為true。可選。 -
data-source:對javax.sql.DataSource的引用,用於訪問資料庫。必需。 -
id:標識底層 Spring bean 定義,它是EventDrivenConsumer或PollingConsumer的一個例項,具體取決於出站通道介面卡的channel屬性是引用SubscribableChannel還是PollableChannel。可選。 -
ignore-column-meta-data:對於完全受支援的資料庫,底層的SimpleJdbcCall類可以自動從 JDBC 元資料中檢索儲存過程或儲存函式的引數資訊。但是,如果資料庫不支援元資料查詢,或者您需要提供自定義引數定義,則可以將此標誌設定為
true。預設為false。可選。 -
is-function:如果為true,則呼叫 SQL 函式。在這種情況下,stored-procedure-name或stored-procedure-name-expression屬性定義所呼叫函式的名稱。預設為false。可選。 -
stored-procedure-name:此屬性指定儲存過程的名稱。如果is-function屬性設定為true,則此屬性改為指定函式名稱。必須指定此屬性或stored-procedure-name-expression。 -
stored-procedure-name-expression:此屬性使用 SpEL 表示式指定儲存過程的名稱。透過使用 SpEL,您可以訪問完整的訊息(如果可用),包括其訊息頭和有效負載。您可以使用此屬性在執行時呼叫不同的儲存過程。例如,您可以將要執行的儲存過程名稱作為訊息頭提供。表示式必須解析為String。如果
is-function屬性設定為true,則此屬性指定一個儲存函式。必須指定此屬性或stored-procedure-name。 -
jdbc-call-operations-cache-size:定義快取的SimpleJdbcCallOperations例項的最大數量。基本上,對於每個儲存過程名稱,都會建立一個新的SimpleJdbcCallOperations例項,然後將其快取。Spring Integration 2.2 添加了 stored-procedure-name-expression屬性和jdbc-call-operations-cache-size屬性。預設快取大小為
10。值為0將停用快取。不允許負值。如果啟用 JMX,有關
jdbc-call-operations-cache的統計資訊將作為 MBean 公開。有關詳細資訊,請參見MBean Exporter。 -
sql-parameter-source-factory:(不適用於儲存過程入站通道介面卡。)對SqlParameterSourceFactory的引用。預設情況下,傳入的Message有效負載的 bean 屬性用作儲存過程輸入引數的源,使用BeanPropertySqlParameterSourceFactory。這可能足以滿足基本用例。對於更復雜的選項,請考慮傳入一個或多個
ProcedureParameter值。請參閱定義引數源。可選。 -
use-payload-as-parameter-source:(不適用於儲存過程入站通道介面卡。)如果設定為true,則Message的有效負載用作提供引數的源。但是,如果設定為false,則整個Message可用作引數的源。如果沒有傳入任何過程引數,則此屬性預設為
true。這意味著,透過使用預設的BeanPropertySqlParameterSourceFactory,有效負載的 bean 屬性用作儲存過程或儲存函式的引數值的源。或者,從版本6.5開始,如果提及的有效負載是Map,則作為鍵。但是,如果傳入了過程引數,此屬性(預設情況下)評估為
false。ProcedureParameter允許提供 SpEL 表示式。因此,訪問整個Message非常有益。該屬性設定在底層的StoredProcExecutor上。可選。
通用配置子元素
儲存過程元件共享一組通用的子元素,您可以使用這些元素定義引數並將其傳遞給儲存過程或儲存函式。以下元素可用
-
引數 -
返回結果集 -
sql-引數-定義 -
輪詢器 -
parameter:提供一種機制來提供儲存過程引數。引數可以是靜態的,也可以使用 SpEL 表示式提供。<int-jdbc:parameter name="" (1) type="" (2) value=""/> (3) <int-jdbc:parameter name="" expression=""/> (4)1 要傳遞給儲存過程或儲存函式的引數名稱。必需。 2 此屬性指定值的型別。如果未提供,則此屬性預設為 java.lang.String。此屬性僅在使用value屬性時使用。可選。3 引數的值。您必須提供此屬性或 expression屬性。可選。4 除了 value屬性,您還可以指定一個 SpEL 表示式來傳遞引數的值。如果指定expression,則不允許使用value屬性。可選。可選。 -
returning-resultset:儲存過程可能會返回多個結果集。透過設定一個或多個returning-resultset元素,您可以指定RowMappers將每個返回的ResultSet轉換為有意義的物件。可選。<int-jdbc:returning-resultset name="" row-mapper="" /> -
sql-parameter-definition:如果您使用的資料庫是完全受支援的,則通常不必指定儲存過程引數定義。相反,這些引數可以自動從 JDBC 元資料中派生。但是,如果您使用的資料庫不是完全受支援的,則必須使用sql-parameter-definition元素顯式設定這些引數。您還可以選擇透過使用
ignore-column-meta-data屬性來關閉透過 JDBC 獲取的引數元資料資訊的任何處理。<int-jdbc:sql-parameter-definition name="" (1) direction="IN" (2) type="STRING" (3) scale="5" (4) type-name="FOO_STRUCT" (5) return-type="fooSqlReturnType"/> (6)
| 1 | 指定 SQL 引數的名稱。必需。 |
| 2 | 指定 SQL 引數定義的方向。預設為IN。有效值為:IN、OUT和INOUT。如果您的過程返回結果集,請使用returning-resultset元素。可選。 |
| 3 | 用於此 SQL 引數定義的 SQL 型別。轉換為整數值,如java.sql.Types所定義。或者,您也可以提供整數值。如果此屬性未明確設定,則預設為“VARCHAR”。可選。 |
| 4 | SQL 引數的比例。僅用於數值和小數引數。可選。 |
| 5 | 對於使用者定義的型別(例如:STRUCT、DISTINCT、JAVA_OBJECT和命名陣列型別)的typeName。此屬性與scale屬性互斥。可選。 |
| 6 | 複雜型別自定義值處理程式的引用。SqlReturnType的實現。此屬性與scale屬性互斥,並且僅適用於 OUT 和 INOUT 引數。可選。
|
定義引數源
引數源控制檢索 Spring Integration 訊息屬性並將其對映到相關儲存過程輸入引數的技術。
儲存過程元件遵循某些規則。預設情況下,Message有效負載的 bean 屬性用作儲存過程輸入引數的源。在這種情況下,使用BeanPropertySqlParameterSourceFactory。這可能足以滿足基本用例。下一個示例說明了這種預設行為。
為了使用BeanPropertySqlParameterSourceFactory進行 bean 屬性的“自動”查詢,您的 bean 屬性必須以小寫字母定義。這是因為在org.springframework.jdbc.core.metadata.CallMetaDataContext(Java 方法為matchInParameterValuesWithCallParameters())中,檢索到的儲存過程引數宣告會轉換為小寫。因此,如果您有駝峰式命名法 bean 屬性(例如lastName),查詢將失敗。在這種情況下,請提供顯式的ProcedureParameter。 |
假設我們有一個有效負載,它由一個具有以下三個屬性的簡單 bean 組成:id、name和description。此外,我們有一個名為INSERT_COFFEE的簡單儲存過程,它接受三個輸入引數:id、name和description。我們還使用了一個完全受支援的資料庫。在這種情況下,儲存過程出站介面卡的以下配置就足夠了
<int-jdbc:stored-proc-outbound-channel-adapter data-source="dataSource"
channel="insertCoffeeProcedureRequestChannel"
stored-procedure-name="INSERT_COFFEE"/>
對於更復雜的選項,請考慮傳入一個或多個ProcedureParameter值。
如果您明確提供了ProcedureParameter值,則預設情況下,將使用ExpressionEvaluatingSqlParameterSourceFactory進行引數處理,以啟用 SpEL 表示式的全部功能。
如果您需要對引數的檢索方式進行更多控制,請考慮透過使用sql-parameter-source-factory屬性傳入SqlParameterSourceFactory的自定義實現。
儲存過程入站通道介面卡
以下列表列出了儲存過程入站通道介面卡的重要屬性
<int-jdbc:stored-proc-inbound-channel-adapter
channel="" (1)
stored-procedure-name=""
data-source=""
auto-startup="true"
id=""
ignore-column-meta-data="false"
is-function="false"
skip-undeclared-results="" (2)
return-value-required="false" (3)
<int:poller/>
<int-jdbc:sql-parameter-definition name="" direction="IN"
type="STRING"
scale=""/>
<int-jdbc:parameter name="" type="" value=""/>
<int-jdbc:parameter name="" expression=""/>
<int-jdbc:returning-resultset name="" row-mapper="" />
</int-jdbc:stored-proc-inbound-channel-adapter>
| 1 | 輪詢訊息傳送到的通道。如果儲存過程或函式不返回任何資料,則Message的有效負載為 null。必需。 |
| 2 | 如果此屬性設定為true,則跳過所有不具有相應SqlOutParameter宣告的儲存過程呼叫結果。例如,儲存過程可以返回更新計數,即使您的儲存過程只聲明瞭一個結果引數。確切的行為取決於資料庫實現。該值設定在底層JdbcTemplate上。該值預設為true。可選。 |
| 3 | 指示是否應包含此過程的返回值。自 Spring Integration 3.0 起。可選。 |
儲存過程出站通道介面卡
以下列表列出了儲存過程出站通道介面卡的重要屬性
<int-jdbc:stored-proc-outbound-channel-adapter channel="" (1)
stored-procedure-name=""
data-source=""
auto-startup="true"
id=""
ignore-column-meta-data="false"
order="" (2)
sql-parameter-source-factory=""
use-payload-as-parameter-source="">
<int:poller fixed-rate=""/>
<int-jdbc:sql-parameter-definition name=""/>
<int-jdbc:parameter name=""/>
</int-jdbc:stored-proc-outbound-channel-adapter>
| 1 | 此端點的接收訊息通道。必需。 |
| 2 | 當此端點作為訂閱者連線到通道時,指定呼叫的順序。當該通道使用failover排程策略時,這尤其重要。當此端點本身是帶有佇列的通道的輪詢消費者時,它不起作用。可選。 |
儲存過程出站閘道器
以下列表列出了儲存過程出站通道介面卡的重要屬性
<int-jdbc:stored-proc-outbound-gateway request-channel="" (1)
stored-procedure-name=""
data-source=""
auto-startup="true"
id=""
ignore-column-meta-data="false"
is-function="false"
order=""
reply-channel="" (2)
reply-timeout="" (3)
return-value-required="false" (4)
skip-undeclared-results="" (5)
sql-parameter-source-factory=""
use-payload-as-parameter-source="">
<int-jdbc:sql-parameter-definition name="" direction="IN"
type=""
scale="10"/>
<int-jdbc:sql-parameter-definition name=""/>
<int-jdbc:parameter name="" type="" value=""/>
<int-jdbc:parameter name="" expression=""/>
<int-jdbc:returning-resultset name="" row-mapper="" />
| 1 | 此端點的接收訊息通道。必需。 |
| 2 | 接收資料庫響應後回覆訊息傳送到的訊息通道。可選。 |
| 3 | 允許您指定此閘道器在成功傳送回覆訊息之前等待的時間(以毫秒為單位),超時則丟擲異常。請記住,在傳送到DirectChannel時,呼叫發生在傳送者的執行緒中。因此,傳送操作失敗可能是由下游的其他元件引起的。可選。 |
| 4 | 指示是否應包含此過程的返回值。可選。 |
| 5 | 如果skip-undeclared-results屬性設定為true,則跳過所有不具有相應SqlOutParameter宣告的儲存過程呼叫結果。例如,儲存過程可能會返回更新計數,即使您的儲存過程只聲明瞭一個結果引數。確切的行為取決於資料庫。該值設定在底層JdbcTemplate上。該值預設為true。可選。 |
示例
本節包含兩個呼叫Apache Derby儲存過程的示例。第一個過程呼叫一個返回ResultSet的儲存過程。透過使用RowMapper,資料被轉換為域物件,然後成為 Spring Integration 訊息有效負載。
在第二個示例中,我們呼叫了一個使用輸出引數而不是返回資料來返回資料的儲存過程。
|
該專案包含此處引用的 Apache Derby 示例,以及如何執行它的說明。Spring Integration Samples 專案還提供了使用 Oracle 儲存過程的示例。 |
在第一個示例中,我們呼叫了一個名為FIND_ALL_COFFEE_BEVERAGES的儲存過程,該過程未定義任何輸入引數,但返回了一個ResultSet。
在 Apache Derby 中,儲存過程是用 Java 實現的。以下列表顯示了方法簽名
public static void findAllCoffeeBeverages(ResultSet[] coffeeBeverages)
throws SQLException {
...
}
以下列表顯示了相應的 SQL
CREATE PROCEDURE FIND_ALL_COFFEE_BEVERAGES() \
PARAMETER STYLE JAVA LANGUAGE JAVA MODIFIES SQL DATA DYNAMIC RESULT SETS 1 \
EXTERNAL NAME 'o.s.i.jdbc.storedproc.derby.DerbyStoredProcedures.findAllCoffeeBeverages';
在 Spring Integration 中,您現在可以使用stored-proc-outbound-gateway呼叫此儲存過程,如下例所示
<int-jdbc:stored-proc-outbound-gateway id="outbound-gateway-storedproc-find-all"
data-source="dataSource"
request-channel="findAllProcedureRequestChannel"
expect-single-result="true"
stored-procedure-name="FIND_ALL_COFFEE_BEVERAGES">
<int-jdbc:returning-resultset name="coffeeBeverages"
row-mapper="org.springframework.integration.support.CoffeBeverageMapper"/>
</int-jdbc:stored-proc-outbound-gateway>
在第二個示例中,我們呼叫了一個名為FIND_COFFEE的儲存過程,該過程有一個輸入引數。它使用輸出引數而不是返回ResultSet。以下示例顯示了方法簽名
public static void findCoffee(int coffeeId, String[] coffeeDescription)
throws SQLException {
...
}
以下列表顯示了相應的 SQL
CREATE PROCEDURE FIND_COFFEE(IN ID INTEGER, OUT COFFEE_DESCRIPTION VARCHAR(200)) \
PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME \
'org.springframework.integration.jdbc.storedproc.derby.DerbyStoredProcedures.findCoffee';
在 Spring Integration 中,您現在可以使用stored-proc-outbound-gateway呼叫此儲存過程,如下例所示
<int-jdbc:stored-proc-outbound-gateway id="outbound-gateway-storedproc-find-coffee"
data-source="dataSource"
request-channel="findCoffeeProcedureRequestChannel"
skip-undeclared-results="true"
stored-procedure-name="FIND_COFFEE"
expect-single-result="true">
<int-jdbc:parameter name="ID" expression="payload" />
</int-jdbc:stored-proc-outbound-gateway>