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
的通道的消息有效负载是一个 map,其中一个键为 something
,因此 []
运算符从该 map 对该值进行取消引用。该头信息也被访问为一个 map。
前一个查询中的参数是传入消息(不是 SpEL 表达式)上的 bean 属性表达式。这种行为是 |
出站适配器需要对 DataSource
或 JdbcTemplate
进行引用。您还可以注入 SqlParameterSourceFactory
来控制将每个传入消息绑定到查询。
如果输入通道是直接通道,那么出站适配器将在同一线程中,因此,与消息发送方处在同一事务(如果存在)中,运行其查询。
Passing Parameters by Using SpEL Expressions
大多数 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>
有关更多信息,请参见 {Defining Parameter Sources}。
Using the PreparedStatement
Callback
有时,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 配置角度来看,<int-jdbc:outbound-channel-adapter>
组件上可以使用 prepared-statement-setter
属性。它允许你指定 MessagePreparedStatementSetter
bean 引用。
Batch Update
从 5.1 版开始,JdbcMessageHandler
如果请求消息的负载是一个 Iterable
实例,则执行 JdbcOperations.batchUpdate()
。如果某个元素不是 Message
,则会将 Iterable
的每个元素包装到一个 Message
中,其中包含来自请求消息的标头。对于基于常规 SqlParameterSourceFactory
的配置,这些消息用来为上述 JdbcOperations.batchUpdate()
函数中使用的参数构建一个 SqlParameterSource[]
。如果应用了 MessagePreparedStatementSetter
配置,则会使用 BatchPreparedStatementSetter
变体为各个项目迭代那些消息,并且会针对这些消息调用提供的 MessagePreparedStatementSetter
。如果选择了 keysGenerated
模式,则不支持批更新。