出站通道适配器

出站通道适配器与入站通道适配器相反:它的作用是处理消息并使用它来执行 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 来控制每个传入消息与查询的绑定。为了更流畅地使用 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 模块提供了配置执行环境(如 ConnectionCallbackPreparedStatementCreator)和操作参数值(如 SqlParameterSource)的 API。它甚至可以访问低级操作的 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 模式时,不支持批量更新。

© . This site is unofficial and not affiliated with VMware.