如需使用最新稳定版本,请使用 Spring Integration 7.0.4spring-doc.cadn.net.cn

出站通道适配器

出站通道适配器是入站适配器的逆操作:其作用是处理消息并利用该消息执行 SQL 查询。 默认情况下,消息负载和请求头可作为输入参数提供给查询,如下例所示:spring-doc.cadn.net.cn

<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为键的映射作为负载,因此[]操作符从该映射中解引用该值。 头信息也作为映射进行访问。spring-doc.cadn.net.cn

前置查询中的参数是传入消息上的 Bean 属性表达式(而非 SpEL 表达式)。 此行为属于 SqlParameterSource,它是由出站适配器创建的默认源。 您可以注入不同的 SqlParameterSourceFactory 以获得不同的行为。

出站适配器需要引用 DataSourceJdbcTemplate。 您也可以注入 SqlParameterSourceFactory 来控制每个传入消息到查询的绑定。spring-doc.cadn.net.cn

如果输入通道是直连通道,则出站适配器将在与消息发送者相同的线程中运行其查询,因此也在相同的事务中(如果存在事务)。spring-doc.cadn.net.cn

使用 SpEL 表达式传递参数

大多数 JDBC 通道适配器的一个常见需求是将参数作为 SQL 查询、存储过程或函数的一部分传递。 如前所述,这些参数默认是 Bean 属性表达式,而不是 SpEL 表达式。 但是,如果您需要传递 SpEL 表达式作为参数,则必须显式注入 SqlParameterSourceFactoryspring-doc.cadn.net.cn

以下示例使用 ExpressionEvaluatingSqlParameterSourceFactory 来实现该需求:spring-doc.cadn.net.cn

<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>

有关更多信息,请参阅 定义参数源spring-doc.cadn.net.cn

使用PreparedStatement回调

有时,SqlParameterSourceFactory的灵活性和松耦合特性无法满足目标PreparedStatement的需求,或者我们需要执行一些底层的JDBC操作。 Spring JDBC模块提供了用于配置执行环境(例如ConnectionCallbackPreparedStatementCreator)以及操纵参数值(例如SqlParameterSource)的API。 它甚至能够访问用于底层操作的API,例如StatementCallbackspring-doc.cadn.net.cn

从 Spring Integration 4.2 开始,MessagePreparedStatementSetter允许在PreparedStatement上手动指定参数,位于requestMessage上下文中。 该类在标准 Spring JDBC API 中扮演的角色与PreparedStatementSetter完全相同。 实际上,当JdbcMessageHandlerJdbcTemplate上调用execute时,它会直接从内联的PreparedStatementSetter实现中被直接调用。spring-doc.cadn.net.cn

此函数式接口选项与 sqlParameterSourceFactory 互斥,可用于作为更强大的替代方案,从 requestMessage 中填充 PreparedStatement 的参数。 例如,当我们需要将 File 数据以流式方式存储到数据库的 BLOB 列时,它非常有用。 以下示例展示了如何实现:spring-doc.cadn.net.cn

@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>组件上是可用的。 它允许您指定一个MessagePreparedStatementSetterbean 引用。spring-doc.cadn.net.cn

批量更新

从 5.1 版本开始,如果请求消息的负载是 Iterable 类型的实例,则 JdbcMessageHandler 将执行 JdbcOperations.batchUpdate()Iterable 中的每个元素都会被包装为 Message,并附带来自请求消息头的信息,前提是该元素尚未是 Message 类型。 在基于常规 SqlParameterSourceFactory 的配置情况下,这些消息用于为所提及的 JdbcOperations.batchUpdate() 函数中的参数构建一个 SqlParameterSource[]。 当应用 MessagePreparedStatementSetter 配置时,会使用 BatchPreparedStatementSetter 变体来遍历这些消息以处理每个项目,并对它们调用提供的 MessagePreparedStatementSetter。 当选择 keysGenerated 模式时,不支持批量更新。spring-doc.cadn.net.cn