跳到主要内容

出站通道适配器

QWen Plus 中英对照 Outbound Channel Adapter

outbound 通道适配器是 inbound 的反向:它的作用是处理一条消息并使用它来执行 SQL 查询。默认情况下,消息的有效负载和标题可作为查询的输入参数,如下例所示:

<int-jdbc:outbound-channel-adapter
query="insert into items (id, status, name) values (:headers[id], 0, :payload[something])"
data-source="dataSource"
channel="input"/>
xml

在前面的例子中,到达标记为 input 的通道的消息的有效负载是一个包含键 something 的映射,因此 [] 操作符从该映射中取消引用该值。头部也作为映射被访问。

备注

前面查询中的参数是传入消息的 bean 属性表达式(不是 SpEL 表达式)。这种行为是 SqlParameterSource 的一部分,这是由 outbound 适配器创建的默认源。你可以注入不同的 SqlParameterSourceFactory 以获得不同的行为。

outbound 适配器需要引用 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>
xml

有关更多信息,请参阅定义参数源

使用 PreparedStatement 回调

有时,SqlParameterSourceFactory 的灵活性和松耦合无法满足目标 PreparedStatement 的需求,或者我们需要执行一些低级别的 JDBC 工作。Spring JDBC 模块提供了 API 来配置执行环境(例如 ConnectionCallbackPreparedStatementCreator)并操作参数值(例如 SqlParameterSource)。它甚至可以访问用于低级操作的 API,例如 StatementCallback

从 Spring Integration 4.2 开始,MessagePreparedStatementSetter 允许在 requestMessage 上下文中手动指定 PreparedStatement 的参数。这个类的作用与标准 Spring JDBC API 中的 PreparedStatementSetter 完全相同。实际上,当 JdbcMessageHandler 调用 JdbcTemplateexecute 方法时,它会直接从内联的 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;
}
java

从 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 模式时,不支持批量更新。