出站通道介面卡
出站通道介面卡與入站通道介面卡相反:它的作用是處理訊息並用它來執行 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
的 Map,因此 []
運算子用於從 Map 中解引用該值。訊息頭也可以作為 Map 訪問。
前面查詢中的引數是傳入訊息上的 bean 屬性表示式(不是 SpEL 表示式)。這種行為是 SqlParameterSource 的一部分,它是出站介面卡建立的預設來源。你可以注入不同的 SqlParameterSourceFactory 來獲取不同的行為。 |
出站介面卡需要引用 DataSource
或 JdbcTemplate
。你也可以注入 SqlParameterSourceFactory
來控制每條傳入訊息與查詢的繫結。
如果輸入通道是 Direct Channel,則出站介面卡將在與訊息傳送者相同的執行緒中執行其查詢,因此也在相同的事務中(如果存在)。
使用 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
的配置情況下,這些訊息被用於構建用於上述 JdbcOperations.batchUpdate()
函式的引數 SqlParameterSource[]
。當應用 MessagePreparedStatementSetter
配置時,將使用 BatchPreparedStatementSetter
變體來迭代這些訊息中的每個專案,並針對它們呼叫提供的 MessagePreparedStatementSetter
。當選擇 keysGenerated
模式時,不支援批次更新。