出站通道介面卡
出站通道介面卡與入站通道介面卡相反:它的作用是處理訊息並使用它來執行 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 來控制每個傳入訊息與查詢的繫結。為了更流暢地使用 SqlParameterSourceFactory(特別是預設的 BeanPropertySqlParameterSourceFactory 及其 MapSqlParameterSource),從版本 6.5 開始,JdbcMessageHandler 公開了一個 usePayloadAsParameterSource 標誌,用於指示是否應將整個訊息作為引數源輸入傳遞。
如果輸入通道是直接通道,出站介面卡會在與訊息傳送者相同的執行緒中執行其查詢,因此也在相同的事務中(如果存在)。
使用 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 模組提供了配置執行環境(如 ConnectionCallback 或 PreparedStatementCreator)和操作引數值(如 SqlParameterSource)的 API。它甚至可以訪問低階操作的 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 模式時,不支援批次更新。