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 以取得不同的行為。

出站配接器需要參考 DataSourceJdbcTemplate。您也可以注入 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 來設定執行環境 (例如 ConnectionCallbackPreparedStatementCreator) 並操作參數值 (例如 SqlParameterSource)。它甚至可以存取用於低階操作的 API,例如 StatementCallback

從 Spring Integration 4.2 開始,MessagePreparedStatementSetter 允許在 requestMessage 環境中手動指定 PreparedStatement 上的參數。此類別扮演的角色與標準 Spring JDBC API 中的 PreparedStatementSetter 完全相同。實際上,當 JdbcMessageHandlerJdbcTemplate 上調用 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 模式時,不支援批次更新。