出站通道适配器
输出通道适配器是输入通道适配器的反向操作:它的作用是处理消息并使用它来执行 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 以获得不同的行为。 |
输出适配器需要引用DataSource
或JdbcTemplate
。您还可以注入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 来配置执行环境(例如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
模式时,不支持批量更新。