Outbound Channel Adapter
出站通道配接器與入站通道配接器相反:其作用是處理訊息並使用它來執行 SQL 查詢。預設情況下,訊息酬載和標頭可用作查詢的輸入參數,如下列範例所示
<int-jdbc:outbound-channel-adapter
query="insert into items (id, status, name) values (:headers[id], 0, :payload[something])"
data-source="dataSource"
channel="input"/>
在先前的範例中,抵達標記為 input
通道的訊息具有一個地圖的酬載,其中包含 something
的鍵,因此 []
運算子會從該地圖取消參考該值。標頭也以地圖的形式存取。
先前查詢中的參數是傳入訊息上的 Bean 屬性運算式 (而非 SpEL 運算式)。此行為是 SqlParameterSource 的一部分,它是出站配接器建立的預設來源。您可以注入不同的 SqlParameterSourceFactory 以取得不同的行為。 |
出站配接器需要參考 DataSource
或 JdbcTemplate
。您也可以注入 SqlParameterSourceFactory
以控制每個傳入訊息到查詢的繫結。
如果輸入通道是直接通道,則出站配接器會在與訊息傳送者相同的執行緒中執行其查詢,因此也會在相同的交易 (如果有的話) 中執行。
使用 SpEL 運算式傳遞參數
大多數 JDBC 通道配接器的常見需求是將參數作為 SQL 查詢或預存程序或函式的一部分傳遞。如先前所述,這些參數預設為 Bean 屬性運算式,而非 SpEL 運算式。但是,如果您需要將 SpEL 運算式作為參數傳遞,則必須明確注入 SqlParameterSourceFactory
。
下列範例使用 ExpressionEvaluatingSqlParameterSourceFactory
來達成該需求
<jdbc:outbound-channel-adapter data-source="dataSource" channel="input"
query="insert into MESSAGES (MESSAGE_ID,PAYLOAD,CREATED_DATE) values (:id, :payload, :createdDate)"
sql-parameter-source-factory="spelSource"/>
<bean id="spelSource"
class="o.s.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="parameterExpressions">
<map>
<entry key="id" value="headers['id'].toString()"/>
<entry key="createdDate" value="new java.util.Date()"/>
<entry key="payload" value="payload"/>
</map>
</property>
</bean>
如需更多資訊,請參閱 定義參數來源。
使用 PreparedStatement
回呼
有時,SqlParameterSourceFactory
的彈性和鬆散耦合無法滿足我們對目標 PreparedStatement
的需求,或者我們需要執行一些低階 JDBC 工作。Spring JDBC 模組提供 API 來設定執行環境 (例如 ConnectionCallback
或 PreparedStatementCreator
) 並操作參數值 (例如 SqlParameterSource
)。它甚至可以存取用於低階操作的 API,例如 StatementCallback
。
從 Spring Integration 4.2 開始,MessagePreparedStatementSetter
允許在 requestMessage
環境中手動指定 PreparedStatement
上的參數。此類別扮演的角色與標準 Spring JDBC API 中的 PreparedStatementSetter
完全相同。實際上,當 JdbcMessageHandler
在 JdbcTemplate
上調用 execute
時,它是直接從內聯 PreparedStatementSetter
實作中調用的。
此函數介面選項與 sqlParameterSourceFactory
互斥,並且可以用作從 requestMessage
填入 PreparedStatement
參數的更強大替代方案。例如,當我們需要以串流方式將 File
資料儲存到資料庫 BLOB
資料行時,它非常有用。下列範例示範如何執行此操作
@Bean
@ServiceActivator(inputChannel = "storeFileChannel")
public MessageHandler jdbcMessageHandler(DataSource dataSource) {
JdbcMessageHandler jdbcMessageHandler = new JdbcMessageHandler(dataSource,
"INSERT INTO imagedb (image_name, content, description) VALUES (?, ?, ?)");
jdbcMessageHandler.setPreparedStatementSetter((ps, m) -> {
ps.setString(1, m.getHeaders().get(FileHeaders.FILENAME));
try (FileInputStream inputStream = new FileInputStream((File) m.getPayload()); ) {
ps.setBlob(2, inputStream);
}
catch (Exception e) {
throw new MessageHandlingException(m, e);
}
ps.setClob(3, new StringReader(m.getHeaders().get("description", String.class)));
});
return jdbcMessageHandler;
}
從 XML 設定的角度來看,prepared-statement-setter
屬性在 <int-jdbc:outbound-channel-adapter>
元件上可用。它可讓您指定 MessagePreparedStatementSetter
Bean 參考。
批次更新
從 5.1 版開始,如果請求訊息的酬載是 Iterable
實例,則 JdbcMessageHandler
會執行 JdbcOperations.batchUpdate()
。如果 Iterable
的每個元素還不是 Message
,則會使用請求訊息中的標頭將其包裝到 Message
中。在基於常規 SqlParameterSourceFactory
的設定中,這些訊息用於建構 SqlParameterSource[]
,以用於提及的 JdbcOperations.batchUpdate()
函數中使用的引數。當應用 MessagePreparedStatementSetter
設定時,會使用 BatchPreparedStatementSetter
變體來針對每個項目迭代這些訊息,並針對它們調用提供的 MessagePreparedStatementSetter
。當選取 keysGenerated
模式時,不支援批次更新。