JDBC 支持
JDBC支持服务
Spring Integration 通过数据库查询提供通道适配器用于接收和发送消息。 通过这些适配器,Spring Integration 不仅支持普通的 JDBC SQL 查询,还支持存储过程和存储函数调用。
你需要把这种依赖性纳入你的项目中:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jdbc</artifactId>
<version>6.0.9</version>
</dependency>
compile "org.springframework.integration:spring-integration-jdbc:6.0.9"
默认情况下,以下JDBC组件可用:
Spring集成JDBC模块还提供JDBC消息存储。
入站通道适配器
入站通道适配器的主要功能是执行 SQL选择查询并将结果集转换为消息。
消息有效载荷是整个结果集(表示为列表),列表中项目的类型取决于行映射策略。
默认策略是一个通用映射器,返回地图对于查询结果中的每一行。
你也可以选择通过添加对行图仪实例(有关行映射的更详细信息,请参见 Spring JDBC 文档)。
如果你想转换选择查询结果到单个消息时,你可以使用下游分流器。 |
入站适配器还需要引用Jdbc模板实例或数据来源.
以及选择为了生成消息,适配器还具有更新该语句标记记录为处理中,使其不会出现在下一次轮询中。
更新可以通过原始选择中的ID列表进行参数化。
默认情况下,这通过命名规范实现(输入结果集中的列,称为身份证在更新的参数映射中转换为一个列表,称为身份证).
以下示例定义了一个带有更新查询和数据来源参考。
<int-jdbc:inbound-channel-adapter query="select * from item where status=2"
channel="target" data-source="dataSource"
update="update item set status=10 where id in (:id)" />
更新查询中的参数用冒号指定(:)在参数名称前加上前缀(在前述示例中,参数是应用于轮询结果集中每一行的表达式)。
这是 Spring JDBC 中命名参数 JDBC 支持的标准功能,结合了 Spring Integration 采用的惯例(将预测到轮询结果列表)。
Spring JDBC 的底层功能限制了可用的表达式(例如,除了句号外的大多数特殊字符都不允许),但由于目标通常是可通过豆路径寻址的对象列表(可能是单个对象的列表),因此这并不过于限制。 |
要更改参数生成策略,可以注入SqlParameterSourceFactory进入适配器以覆盖默认行为(适配器具有SQL-参数-源-工厂属性)。
Spring Integration 提供ExpressionEvaluatingSqlParameterSourceFactory创建基于SpEL的参数源,查询结果为#root对象。
(如果每行更新为真,根对象是行)。
如果相同参数名称在更新查询中多次出现,则只计算一次,结果会被缓存。
你也可以用参数源来做选择查询。 在这种情况下,由于没有“结果”对象可供评估,每次都使用单一参数源(而非使用参数源工厂)。 从4.0版本开始,你可以用Spring创建基于SpEL的参数源,如下示例所示:
<int-jdbc:inbound-channel-adapter query="select * from item where status=:status"
channel="target" data-source="dataSource"
select-sql-parameter-source="parameterSource" />
<bean id="parameterSource" factory-bean="parameterSourceFactory"
factory-method="createParameterSourceNoCache">
<constructor-arg value="" />
</bean>
<bean id="parameterSourceFactory"
class="o.s.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="parameterExpressions">
<map>
<entry key="status" value="@statusBean.which()" />
</map>
</property>
</bean>
<bean id="statusBean" class="foo.StatusDetermination" />
这值每个参数表达式中都可以是任何有效的SpEL表达式。
这#root表达式评估的对象是定义在参数源豆。
对于所有评估都是静态的(在前述示例中,空值)字符串).
从5.0版本开始,你可以提供ExpressionEvaluatingSqlParameterSourceFactory跟sqlParameterTypes指定特定参数的目标SQL类型。
以下示例为查询中使用的参数提供了SQL类型:
<int-jdbc:inbound-channel-adapter query="select * from item where status=:status"
channel="target" data-source="dataSource"
select-sql-parameter-source="parameterSource" />
<bean id="parameterSource" factory-bean="parameterSourceFactory"
factory-method="createParameterSourceNoCache">
<constructor-arg value="" />
</bean>
<bean id="parameterSourceFactory"
class="o.s.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="sqlParameterTypes">
<map>
<entry key="status" value="#{ T(java.sql.Types).BINARY}" />
</map>
</property>
</bean>
使用该createParameterSourceNoCache工厂方法。
否则,参数源会缓存评估结果。
还要注意,由于缓存被禁用,如果同一参数名称多次出现在 select 查询中,每次都会重新评估。 |
民调与交易
入站适配器接受普通的 Spring Integration 轮询器作为子元素。 因此,投票频率可以被控制(以及其他用途)。 在JDBC使用中,轮询器的一个重要功能是可以将轮询作包裹在事务中,如下示例所示:
<int-jdbc:inbound-channel-adapter query="..."
channel="target" data-source="dataSource" update="...">
<int:poller fixed-rate="1000">
<int:transactional/>
</int:poller>
</int-jdbc:inbound-channel-adapter>
| 如果没有明确指定轮询器,则使用默认值。 与Spring Integration的常见做法一样,它可以被定义为顶层豆子。 |
在前述示例中,数据库每1000毫秒(或每秒一次)轮询一次,更新和选择查询在同一事务中执行。 事务管理器配置未显示。 然而,只要它知道数据源,轮询就是事务性的。 一个常见的用例是将下游通道设置为直接通道(默认),这样端点在同一线程中被调用,从而实现同一事务。 这样,如果其中任何一个失败,事务会回滚,输入数据会恢复到原始状态。
最大行数对每轮询最大消息数
JDBC入站通道适配器定义了一个属性,称为最大行数.
当你指定适配器的轮询器时,还可以定义一个名为每轮询最大消息数.
虽然这两个属性看起来相似,但它们的含义却截然不同。
每轮询最大消息数指定每个轮询间隔内查询执行次数,而最大行数指定每次执行返回的行数。
在正常情况下,你很可能不想设置轮询器每轮询最大消息数当你使用 JDBC 入站通道适配器时,属性。
其默认值为1,这意味着JDBC的入站通道适配器接收()每个轮询间隔只执行一次方法。
设置每轮询最大消息数属性到更大的值意味着查询连续执行了同样多次。
欲了解更多关于每轮询最大消息数属性,参见配置入站通道适配器。
相比之下,最大行数属性,如果大于0,指定了由接收()方法。
如果属性被设置为0,所有行都包含在最终消息中。
该属性默认为0.
建议通过厂商特定的查询选项(例如 MySQL)使用结果集限制限制或 SQL Server返回页首或者说是神谕者的罗纳姆.
更多信息请参见特定提供商文档。 |
出站通道适配器
出站通道适配器是入站的反过来:其角色是处理消息并用来执行SQL查询。 默认情况下,消息有效载荷和头部作为查询的输入参数可用,如下示例所示:
<int-jdbc:outbound-channel-adapter
query="insert into foos (id, status, name) values (:headers[id], 0, :payload[something])"
data-source="dataSource"
channel="input"/>
在上述例子中,抵达信道的消息标记为输入有一个映射的有效载荷,键为东西,因此算符从映射中剔除该值。
头部也可以作为映射访问。[]
前述查询中的参数是对接收消息的豆属性表达式(而非 SpEL 表达式)。
这种行为是SqlParameterSource,这是出站适配器创建的默认源。
你可以注射不同的SqlParameterSourceFactory为了获得不同的行为。 |
出站适配器需要引用以下两者数据来源或者Jdbc模板.
你也可以注射SqlParameterSourceFactory控制每个入站消息与查询的绑定。
如果输入通道是直接通道,出站适配器在与消息发送方相同的线程中运行查询,因此(如果有交易的话)也是相同的。
通过使用 SpEL 表达式传递参数
大多数JDBC通道适配器的一个常见要求是通过SQL查询或存储过程或函数传递参数。
如前所述,这些参数默认是豆属性表达式,而非 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>
更多信息请参见参数来源定义。
使用准备陈述回调
有时,灵活性和松耦合性SqlParameterSourceFactory无法满足目标的需求准备陈述或者我们需要做一些底层的JDBC工作。Spring JDBC模块提供了配置执行环境的API(例如:连接回调或PreparedStatementCreator)并作参数值(例如SqlParameterSource). 它甚至可以访问用于低层作的API,例如:声明回应.
从 Spring Integration 4.2 开始,MessagePreparedStatementSetter允许对准备陈述手动,在请求消息上下文。 这个类在PreparedStatementSetter在标准的 Spring JDBC API 中。实际上,它是直接从内联调用的PreparedStatementSetter当JdbcMessageHandler调用执行在Jdbc模板.
该功能接口选项与 互斥sql参数SourceFactory(元元工厂)可以作为更强大的替代方案来填充参数准备陈述来自请求消息. 例如,当我们需要存储时,它非常有用文件数据到数据库黏液以流式方式进行列。以下示例展示了如何实现:
@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:出站-通道-适配器>元件。 它允许你指定一个MessagePreparedStatementSetter比恩的引用。
批次更新
从5.1版本开始,JdbcMessageHandler执行JdbcOperations.batchUpdate()如果请求消息的有效载荷是可迭代实例。 每个元素可迭代被包裹为消息如果该元素不是消息已经。 在正则的情况下SqlParameterSourceFactory基于配置的这些消息用于构建SqlParameterSource[]对于上述论证JdbcOperations.batchUpdate()功能。 当MessagePreparedStatementSetter应用配置,aBatchPreparedStatementSetter变体用于对每个项目的这些消息进行迭代,且MessagePreparedStatementSetter针对它们调用。批处理更新不被支持,当键生成模式已选定。
出站网关
出站网关就像是出站和入站适配器的组合:其职责是处理消息并用它执行SQL查询,然后通过发送结果到回复通道来响应。默认情况下,消息有效载荷和报头作为查询的输入参数可用,如下示例所示:
<int-jdbc:outbound-gateway
update="insert into mythings (id, status, name) values (:headers[id], 0, :payload[thing])"
request-channel="input" reply-channel="output" data-source="dataSource" />
前述示例的结果是将记录插入到我的事表并返回一条消息,表示受影响行数(有效载荷为映射:{更新=1})到输出通道。
如果更新查询是带有自动生成键的插入,你可以通过添加添加生成键来填充回复消息keys-generated=“true”切换到前述示例(这不是默认设置,因为某些数据库平台不支持)。以下示例展示了更改后的配置:
<int-jdbc:outbound-gateway
update="insert into mythings (status, name) values (0, :payload[thing])"
request-channel="input" reply-channel="output" data-source="dataSource"
keys-generated="true"/>
你也可以选择一个选择查询,从结果中执行并生成回复消息(例如入站适配器),如下示例所示:
<int-jdbc:outbound-gateway
update="insert into foos (id, status, name) values (:headers[id], 0, :payload[foo])"
query="select * from foos where id=:headers[$id]"
request-channel="input" reply-channel="output" data-source="dataSource"/>
自 Spring Integration 2.2 起,SQL 更新查询不再是强制的。你现在只能通过以下任一查询属性或查询元素。 如果你需要主动检索数据,例如使用通用网关或有效载荷增强器,这非常有用。回复消息随后由结果生成(类似于入站适配器的工作原理),并传递给回复通道。以下示例展示了如何使用查询属性:
<int-jdbc:outbound-gateway
query="select * from foos where id=:headers[id]"
request-channel="input"
reply-channel="output"
data-source="dataSource"/>
|
默认情况下,该组件 |
和通道适配器一样,你也可以提供SqlParameterSourceFactory请求和回复的实例。默认设置与出站适配器相同,因此请求消息可作为表达式的根节点。 如果keys-generated=“true”,表达式的根是生成的键(如果只有一个则是映射,若多值则为列表)。
出站网关需要引用以下任一数据来源或者Jdbc模板. 它也可以有SqlParameterSourceFactory注入以控制输入消息与查询的绑定。
从4.2版本开始,请求-准备-语句设置器属性可在<int-jdbc:outbound-gateway>作为替代方案request-sql-parameter-source-factory. 它允许你指定一个MessagePreparedStatementSetterBEAN Reference,实现了更复杂的功能准备陈述执行前的准备。
从6.0版本开始,Jdbc外发网关返回一个空列表结果,而不是将其转换为零这与之前的“无回复”含义相同。这在处理空列表是下游逻辑一部分的应用中,会增加额外的配置。关于可能的空列表处理选项,请参见分路器丢弃通道。
更多信息请参见外呼通道适配器MessagePreparedStatementSetter.
JDBC消息库
Spring Integration 提供两种 JDBC 专用的消息存储实现。 这Jdbc消息存储适合用于聚合器和理赔检查模式。 这Jdbc频道消息存储实现为消息通道提供了更有针对性和可扩展性的实现。
注意你可以使用Jdbc消息存储支持消息通道,Jdbc频道消息存储为此目的进行了优化。
从5.0.11、5.1.2版本开始,索引Jdbc频道消息存储已经优化了。如果你在这样的存储中有大型消息组,你可能需要修改索引。此外,索引优先频道注释被剔除,因为除非你使用由JDBC支持的此类频道,否则不需要注释。 |
当使用OracleChannelMessageStoreQueryProvider,必须添加优先通道索引,因为它包含在查询中的提示中。 |
数据库初始化
在开始使用 JDBC 消息存储组件之前,你应该先配置一个包含相应对象的目标数据库。
Spring Integration 附带了一些示例脚本,可用于初始化数据库。 在Spring-integration-JDBCJAR文件中,你可以在org.springframework.integration.jdbc包。 它为多种常见数据库平台提供了示例创建脚本和示例丢弃脚本。使用这些脚本的常见方式是在 Spring JDBC 数据源初始化工具中引用它们。请注意,脚本以示例形式提供,并作为所需表和列名称的规范。你可能会发现需要在生产环境中增强它们(例如通过添加索引声明)。
通用JDBC消息库
JDBC模块实现了Spring集成消息商店(在理赔检查模式中很重要)MessageGroupStore(在有状态模式如聚合器中很重要)由数据库支持。这两个接口均由Jdbc消息存储并且支持用XML配置存储实例,如下示例所示:
<int-jdbc:message-store id="messageStore" data-source="dataSource"/>
你可以指定一个Jdbc模板而不是数据来源.
以下示例展示了一些其他可选属性:
<int-jdbc:message-store id="messageStore" data-source="dataSource"
lob-handler="lobHandler" table-prefix="MY_INT_"/>
在前面的例子中,我们指定了一个LobHandler用于处理大对象的消息(这对 Oracle 来说通常是必要的),以及存储生成的查询中表名称的前缀。表名前缀默认为INT_.
备份消息通道
如果你打算用JDBC支持消息频道,我们建议使用Jdbc频道消息存储实现。 它仅与消息通道配合使用。
支持的数据库
这Jdbc频道消息存储使用数据库特定的SQL查询来检索数据库中的消息。因此,您必须设置ChannelMessageStoreQueryProvider属性Jdbc频道消息存储. 这channelMessageStoreQueryProvider提供您指定的特定数据库的SQL查询。Spring Integration支持以下关系型数据库:
-
PostgreSQL
-
HSQLDB
-
MySQL
-
神谕
-
德比
-
H2
-
SqlServer
-
Sybase
-
DB2
如果你的数据库没有被列出,你可以扩展摘要通道信息存储查询提供者类并提供你自己的自定义查询。
4.0版本增加了MESSAGE_SEQUENCE确保即使消息存储在同一毫秒内,也能实现先进先出(FIFO)排队。
自定义消息插入
自5.0版本起,通过超载ChannelMessageStorePreparedStatementSetter类中,你可以在Jdbc频道消息存储.
你可以用它设置不同的列,或者更改表结构或序列化策略。
例如,默认序列化为字节[]你可以将其结构存储为 JSON 字符串。
以下示例使用默认实现集合值用于存储常见列,并覆盖将消息有效载荷存储为瓦尔查尔:
public class JsonPreparedStatementSetter extends ChannelMessageStorePreparedStatementSetter {
@Override
public void setValues(PreparedStatement preparedStatement, Message<?> requestMessage,
Object groupId, String region, boolean priorityEnabled) throws SQLException {
// Populate common columns
super.setValues(preparedStatement, requestMessage, groupId, region, priorityEnabled);
// Store message payload as varchar
preparedStatement.setString(6, requestMessage.getPayload().toString());
}
}
并行投票
在轮询消息通道时,你可以选择配置关联的轮询器其中任务执行者参考。
|
不过请记住,如果你使用JDBC支持的消息通道,并且计划通过多个线程进行交换性轮询通道及消息存储,你应确保使用支持多版本并发控制(MVCC)的关系数据库。 否则,可能会有锁住的问题,使用多线程时性能可能无法如预期实现。 例如,阿帕奇德比在这方面存在问题。 为了实现更好的JDBC队列吞吐量,避免不同线程轮询相同数据时出现问题
|
优先频道
从4.0版本开始,Jdbc频道消息存储实现优先能力通道消息存储并提供优先启用选择权,允许它作为消息存储参考文献优先队列实例。
为此,INT_CHANNEL_MESSAGE表有MESSAGE_PRIORITY列 以存储 的值优先权消息头。
此外,还有一个新的MESSAGE_SEQUENCE列使我们能够实现稳健的先进先出(FIFO)轮询机制,即使在同一毫秒内存储多个消息,且优先级相同。
消息从数据库中轮询(选择),使用MESSAGE_PRIORITY DESC 的顺序是最后、CREATED_DATE、MESSAGE_SEQUENCE.
我们不建议使用相同的产品Jdbc频道消息存储优先级和非优先级队列通道的 BEAN 是因为优先启用选项适用于整个存储,且队列通道不保留正确的先进先出队列语义。
不过,还是一样INT_CHANNEL_MESSAGE桌面(甚至地区)可以同时用于这两种情况Jdbc频道消息存储类型。
要配置该场景,你可以从一个消息存储豆扩展到另一个,如下示例所示: |
<bean id="channelStore" class="o.s.i.jdbc.store.JdbcChannelMessageStore">
<property name="dataSource" ref="dataSource"/>
<property name="channelMessageStoreQueryProvider" ref="queryProvider"/>
</bean>
<int:channel id="queueChannel">
<int:queue message-store="channelStore"/>
</int:channel>
<bean id="priorityStore" parent="channelStore">
<property name="priorityEnabled" value="true"/>
</bean>
<int:channel id="priorityChannel">
<int:priority-queue message-store="priorityStore"/>
</int:channel>
消息存储的分区
通常会使用Jdbc消息存储作为同一应用中一组应用程序或节点的全局存储。
为了防止名称冲突并控制数据库元数据配置,消息存储允许表以两种方式进行分区。
一种方法是使用不同的表名,通过更改前缀(如前所述)。
另一种方法是指定地区用于在单一表中分区数据的名称。
第二种方法的一个重要用例是当消息商店管理支持Spring集成消息通道的持久队列。
持久信道的消息数据在信道名称的存储中被键入。
因此,如果频道名称不是全球唯一的,频道可能会接收到不属于它们的数据。
为了避免这种风险,你可以使用消息存储地区为了让不同物理通道的数据分开,这些通道具有相同的逻辑名称。
PostgreSQL:接收推送通知
PostgreSQL 提供了一个监听和通知框架,用于在数据库表作时接收推送通知。
Spring Integration利用该机制(从6.0版本开始)允许在新增消息添加到Jdbc频道消息存储.
使用此功能时,必须定义数据库触发器,该触发器可在schema-postgresql.sql该文件包含在 Spring Integration 的 JDBC 模块中。
推送通知通过PostgresChannelMessageTableSubscriber该类允许其用户在收到任何给定新消息时收到回调地区和组ID.
即使消息被附加在不同的JVM上,但发送到同一数据库,这些通知也会被接收。
这PostgresSubscribableChannel(订阅频道)实现方式为PostgresChannelMessageTableSubscriber.Subscription合同中会对上述通知的反应从商店拉取消息PostgresChannelMessageTableSubscriber通知。
例如,推送通知某个群体可以按以下方式接收:
@Bean
public JdbcChannelMessageStore messageStore(DataSource dataSource) {
JdbcChannelMessageStore messageStore = new JdbcChannelMessageStore(dataSource);
messageStore.setChannelMessageStoreQueryProvider(new PostgresChannelMessageStoreQueryProvider());
return messageStore;
}
@Bean
public PostgresChannelMessageTableSubscriber subscriber(
@Value("${spring.datasource.url}") String url,
@Value("${spring.datasource.username}") String username,
@Value("${spring.datasource.password}") String password) {
return new PostgresChannelMessageTableSubscriber(() ->
DriverManager.getConnection(url, username, password).unwrap(PgConnection.class));
}
@Bean
public PostgresSubscribableChannel channel(
PostgresChannelMessageTableSubscriber subscriber,
JdbcChannelMessageStore messageStore) {
return new PostgresSubscribableChannel(messageStore, "some group", subscriber);
}
事务支持
从6.0.5版本开始,指定了PlatformTransactionManager在PostgresSubscribableChannel(订阅频道)将在交易中通知订阅者。
订阅者出现异常会导致交易被回滚,消息会被重新放回消息存储。
交易支持默认不会被激活。
重试
从6.0.5版本开始,重试策略可以通过提供重试模板前往PostgresSubscribableChannel(订阅频道).
默认情况下,不进行重试。
|
任何活跃的 为了实现独占连接的需求,也建议JVM只运行一个连接 |
存储过程
在某些情况下,单纯的JDBC支持是不够的。 也许你处理的是遗留的关系型数据库模式,或者有复杂的数据处理需求,但归根结底,你必须使用存储过程或存储函数。 自 Spring Integration 2.1 以来,我们提供了三个组件来执行存储过程或存储函数:
-
存储过程入信道适配器
-
存储过程 出站通道适配器
-
存储过程出站网关
支持的数据库
为了启用对存储过程和存储函数的调用,存储过程组件使用org.springframework.jdbc.core.simple.SimpleJdbcCall类。
因此,以下数据库完全支持用于执行存储过程:
-
阿帕奇德比
-
DB2
-
MySQL
-
Microsoft SQL Server
-
神谕
-
PostgreSQL
-
Sybase
如果你想执行存储函数,以下数据库是完全支持的:
-
MySQL
-
Microsoft SQL Server
-
神谕
-
PostgreSQL
|
即使你的数据库可能不完全支持,只要你的关系数据库系统支持存储过程或存储函数,你很可能仍然可以相当成功地使用Spring集成的存储过程组件。 事实上,一些提供的集成测试使用H2数据库。 然而,彻底测试这些使用场景非常重要。 |
常见配置属性
所有存储过程组件共享某些配置参数:
-
自动启动: 生命周期属性,指示该组件是否应在应用上下文启动时启动。 它默认为true. 自选。 -
数据来源: 指一个javax.sql.数据源,用于访问数据库。 必填。 -
身份证: 表示 Spring Bean 底层定义,即 以下EventDrivenConsumer或民调消费者,取决于出站通道适配器是否渠道属性引用 a订阅频道或者Pollable频道. 自选。 -
忽略列元数据对于完全支持的数据库,底层SimpleJdbcCall类可以自动从JDBC元数据中获取存储过程或存储函数的参数信息。然而,如果数据库不支持元数据查找,或者你需要提供自定义参数定义,则可以将该标志设置为
true. 它默认为false. 自选。 -
is-函数:如果true调用了一个SQL函数。 在这种情况下,存储过程名称或存储过程命名表达式属性定义了被调用函数的名称。 它默认为false. 自选。 -
存储过程名称: 该属性指定存储过程的名称。 如果is-函数属性设置为true,该属性指定函数名称。 要么是这个性质,要么存储过程命名表达式必须说明。 -
存储过程命名表达式: 该属性通过使用 SpEL 表达式指定存储过程的名称。 使用 SpEL 可以访问完整消息(如果有的话),包括其头部和有效载荷。 你可以利用该属性在运行时调用不同的存储过程。 例如,你可以提供想要作为消息头执行的存储过程名称。 该表达式必须解析为字符串.如果
is-函数属性设置为true,该属性指定一个存储函数。 要么是这个性质,要么存储过程名称必须说明。 -
jdbc-调用作-缓存大小: 定义了最大缓存数量SimpleJdbcCallOperations实例。 基本上,每个存储过程名称,都有一个新的SimpleJdbcCallOperations创建实例,作为回报,该实例被缓存。Spring Integration 2.2 增加了 存储过程命名表达式属性和jdbc-调用作-缓存大小属性。默认缓存大小为
10. 一个值为0关闭缓存。 不允许使用负数值。如果你启用JMX,就能获得关于
JDBC-调用作缓存被揭露为MBean。 更多信息请参见MBean出口商。 -
SQL-参数-源-工厂:(存储过程入站通道适配器不可用。) 对SqlParameterSourceFactory. 默认情况下,传入的豆子属性消息有效载荷作为存储过程输入参数的来源,通过BeanPropertySqlParameterSourceFactory.这对于基本的使用场景来说可能足够。 对于更复杂的选项,可以考虑通过一个或多个
ProcedureParameter值。 参见定义参数来源。 自选。 -
使用有效载荷作为参数源:(存储过程入站通道适配器不可用。) 如果设置为true, 是 的有效载荷消息作为参数的来源。 如果设置为false然而,整个消息作为参数的来源。如果没有传递过程参数,该属性默认为
true. 这意味着,通过使用默认值BeanPropertySqlParameterSourceFactory,有效载荷的豆属性被用作存储过程或存储函数参数值的来源。然而,如果传递了过程参数,该性质(默认情况下)计算为
false.ProcedureParameter允许提供特殊语言表达式。 因此,能够访问全部内容非常有益消息. 该性质是基于标的的StoredProcExecutor. 自选。
常见配置子元素
存储过程组件共享一组共同的子元素,你可以用这些子元素定义并传递给存储过程或存储函数的参数。 以下元素可用:
-
参数 -
返回结果集 -
SQL参数定义 -
轮询者 -
参数:提供一种机制来提供存储过程参数。 参数可以是静态的,也可以通过使用 SpEL 表达式来提供。<int-jdbc:parameter name="" (1) type="" (2) value=""/> (3) <int-jdbc:parameter name="" expression=""/> (4)+ <1> 要传递到存储过程或存储函数中的参数名称。 必填。 <2> 该属性指定值的类型。 如果没有提供任何信息,该属性默认为
java.lang.字符串. 该属性仅在值属性被使用。 自选。 <3>参数值。 您必须提供该属性或表达属性。 自选。 <4> 而不是值属性,你可以指定一个 SpEL 表达式来传递参数的值。 如果你指定表达这值不允许属性。 自选。自选。
-
返回结果集:存储过程可以返回多个结果集。 通过设置一个或多个返回结果集元素,你可以指定RowMappers 行列图每人回归以转化结果集到有意义的对象。 自选。<int-jdbc:returning-resultset name="" row-mapper="" /> -
SQL参数定义:如果你使用完全支持的数据库,通常不需要指定存储过程参数定义。 相反,这些参数可以自动从JDBC元数据中推导出来。 然而,如果你使用的数据库未完全支持,你必须通过使用SQL参数定义元素。你也可以选择关闭通过JDBC获得的参数元数据信息处理,方法是使用
忽略列元数据属性。<int-jdbc:sql-parameter-definition name="" (1) direction="IN" (2) type="STRING" (3) scale="5" (4) type-name="FOO_STRUCT" (5) return-type="fooSqlReturnType"/> (6)1 指定SQL参数的名称。 必填。 2 指定SQL参数定义的方向。 默认 在. 有效数值如下:在,外和内. 如果你的程序返回的是结果集,可以使用返回结果集元素。 自选。3 用于此SQL参数定义的SQL类型。 转换为整数值,定义为 java.sql.类型. 或者,你也可以提供整数值。 如果该属性未被显式设置,则默认为“VARCHAR”。 自选。4 SQL参数的规模。 仅用于数值和小数参数。 自选。 5 这 类型名称对于用户命名的类型,例如:结构,不同,JAVA_OBJECT,以及命名的数组类型。 该属性与规模属性。 自选。6 引用复杂类型的自定义值处理程序。 一个实现 SqlReturnType. 该属性与规模属性 和 仅适用于 OUT 和 INOUT 参数。 自选。 -
轮询者:如果你的端点是民调消费者. 自选。
参数来源的定义
参数源负责检索和映射 Spring Integration 消息属性到相关存储过程输入参数的技术。
存储过程组件遵循一定规则。
默认情况下,豆子的性质消息有效载荷被用作存储过程输入参数的源。
在这种情况下,一个BeanPropertySqlParameterSourceFactory被使用。
这对于基本的使用场景来说可能足够。
下一个例子说明了这种默认行为。
对于“自动”查找豆属性,使用BeanPropertySqlParameterSourceFactory要工作,你的豆子属性必须用小写字母定义。
这是因为在org.springframework.jdbc.core.metadata.CallMetaDataContext(Java 方法为matchInParameterValuesWithCallParameters()检索的存储过程参数声明会转换为小写字母。
因此,如果你有骆驼壳豆特性(例如:姓氏),查找失败。
在这种情况下,提供一个明确的ProcedureParameter. |
假设我们有一个有效载荷,由一个具有以下三个性质的简单豆子组成:身份证,名称和描述.
此外,我们还有一个简单的存储过程,称为INSERT_COFFEE该系统接受三个输入参数:身份证,名称和描述.
我们还使用一个完全支持的数据库。
在这种情况下,以下存储过程出站适配器的配置就足够了:
<int-jdbc:stored-proc-outbound-channel-adapter data-source="dataSource"
channel="insertCoffeeProcedureRequestChannel"
stored-procedure-name="INSERT_COFFEE"/>
对于更复杂的选项,可以考虑通过一个或多个ProcedureParameter值。
如果你提供ProcedureParameter显式地,默认情况下,一个ExpressionEvaluatingSqlParameterSourceFactory用于参数处理,以实现SpEL表达式的全部功能。
如果你还需要更多参数获取的控制,可以考虑传递一个自定义实现SqlParameterSourceFactory通过使用SQL-参数-源-工厂属性。
存储过程入信道适配器
以下列表列出了存储过程入站通道适配器的重要属性:
<int-jdbc:stored-proc-inbound-channel-adapter
channel="" (1)
stored-procedure-name=""
data-source=""
auto-startup="true"
id=""
ignore-column-meta-data="false"
is-function="false"
skip-undeclared-results="" (2)
return-value-required="false" (3)
<int:poller/>
<int-jdbc:sql-parameter-definition name="" direction="IN"
type="STRING"
scale=""/>
<int-jdbc:parameter name="" type="" value=""/>
<int-jdbc:parameter name="" expression=""/>
<int-jdbc:returning-resultset name="" row-mapper="" />
</int-jdbc:stored-proc-inbound-channel-adapter>
| 1 | 轮询消息发送到的信道。
如果存储过程或函数没有返回任何数据,则消息是空。
必填。 |
| 2 | 如果该属性被设置为true,所有存储过程调用的结果都没有对应SqlOutParameter声明被绕过。
例如,存储过程可以返回更新计数值,尽管你的存储过程只声明了一个结果参数。
具体行为取决于数据库的实现方式。
价值是基于标的资产Jdbc模板.
该值默认为true.
自选。 |
| 3 | 表示是否应包含该过程的返回值。 自从春季集成3.0以来, 自选。 |
存储过程出站通道适配器
以下列表列出了存储过程出站通道适配器的重要属性:
<int-jdbc:stored-proc-outbound-channel-adapter channel="" (1)
stored-procedure-name=""
data-source=""
auto-startup="true"
id=""
ignore-column-meta-data="false"
order="" (2)
sql-parameter-source-factory=""
use-payload-as-parameter-source="">
<int:poller fixed-rate=""/>
<int-jdbc:sql-parameter-definition name=""/>
<int-jdbc:parameter name=""/>
</int-jdbc:stored-proc-outbound-channel-adapter>
| 1 | 该端点的接收消息信道。 必填。 |
| 2 | 指定当该端点作为信道的订阅者连接时的调用顺序。
当该通道使用一个备援切换派遣策略。
当该端点本身是带队列的信道的轮询消费者时,这无效。
自选。 |
存储过程出站网关
以下列表列出了存储过程出站通道适配器的重要属性:
<int-jdbc:stored-proc-outbound-gateway request-channel="" (1)
stored-procedure-name=""
data-source=""
auto-startup="true"
id=""
ignore-column-meta-data="false"
is-function="false"
order=""
reply-channel="" (2)
reply-timeout="" (3)
return-value-required="false" (4)
skip-undeclared-results="" (5)
sql-parameter-source-factory=""
use-payload-as-parameter-source="">
<int-jdbc:sql-parameter-definition name="" direction="IN"
type=""
scale="10"/>
<int-jdbc:sql-parameter-definition name=""/>
<int-jdbc:parameter name="" type="" value=""/>
<int-jdbc:parameter name="" expression=""/>
<int-jdbc:returning-resultset name="" row-mapper="" />
| 1 | 该端点的接收消息信道。 必填。 |
| 2 | 收到数据库响应后应发送回复的消息通道。 自选。 |
| 3 | 它允许你指定网关在回复消息成功发送前等待多长时间,然后才抛出异常。
请记住,发送给直达频道调用发生在发送方线程中。
因此,发送作失败可能是由下游的其他组件引起的。
默认情况下,网关会无限期等待。
该数值以毫秒为单位。
自选。 |
| 4 | 表示是否应包含该过程的返回值。 自选。 |
| 5 | 如果跳过未申报结果属性设置为true,所有存储过程调用的结果都没有对应SqlOutParameter声明被绕过。
例如,存储过程可能会返回更新计数值,尽管你的存储过程只声明了一个结果参数。
具体行为取决于数据库。
价值是基于标的资产Jdbc模板.
该值默认为true.
自选。 |
例子
本节包含两个调用Apache Derby存储过程的示例。
第一个过程调用一个存储过程,返回结果集.
通过使用行图仪数据被转换为域对象,随后成为 Spring Integration 消息的有效载荷。
在第二个示例中,我们调用一个存储过程,使用输出参数返回数据。
|
可以看看Spring集成样本项目。 该项目包含这里提到的Apache Derby示例,以及运行说明。 Spring 集成示例项目也提供了使用 Oracle 存储过程的示例。 |
在第一个例子中,我们调用一个名为FIND_ALL_COFFEE_BEVERAGES该参数不定义任何输入参数,但返回结果集.
在Apache Derby中,存储过程是用Java实现的。 以下列表展示了方法签名:
public static void findAllCoffeeBeverages(ResultSet[] coffeeBeverages)
throws SQLException {
...
}
以下列表展示了对应的 SQL:
CREATE PROCEDURE FIND_ALL_COFFEE_BEVERAGES() \
PARAMETER STYLE JAVA LANGUAGE JAVA MODIFIES SQL DATA DYNAMIC RESULT SETS 1 \
EXTERNAL NAME 'o.s.i.jdbc.storedproc.derby.DerbyStoredProcedures.findAllCoffeeBeverages';
在 Spring Integration 中,你现在可以通过使用例如的一个方式调用该存储过程stored-proc-outbound-gateway,如下示例所示:
<int-jdbc:stored-proc-outbound-gateway id="outbound-gateway-storedproc-find-all"
data-source="dataSource"
request-channel="findAllProcedureRequestChannel"
expect-single-result="true"
stored-procedure-name="FIND_ALL_COFFEE_BEVERAGES">
<int-jdbc:returning-resultset name="coffeeBeverages"
row-mapper="org.springframework.integration.support.CoffeBeverageMapper"/>
</int-jdbc:stored-proc-outbound-gateway>
在第二个例子中,我们调用一个名为FIND_COFFEE只有一个输入参数。
而不是退回结果集它使用输出参数。
以下示例展示了方法签名:
public static void findCoffee(int coffeeId, String[] coffeeDescription)
throws SQLException {
...
}
以下列表展示了对应的 SQL:
CREATE PROCEDURE FIND_COFFEE(IN ID INTEGER, OUT COFFEE_DESCRIPTION VARCHAR(200)) \
PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME \
'org.springframework.integration.jdbc.storedproc.derby.DerbyStoredProcedures.findCoffee';
在 Spring Integration 中,你现在可以通过使用例如的一个方式调用这个存储过程stored-proc-outbound-gateway,如下示例所示:
<int-jdbc:stored-proc-outbound-gateway id="outbound-gateway-storedproc-find-coffee"
data-source="dataSource"
request-channel="findCoffeeProcedureRequestChannel"
skip-undeclared-results="true"
stored-procedure-name="FIND_COFFEE"
expect-single-result="true">
<int-jdbc:parameter name="ID" expression="payload" />
</int-jdbc:stored-proc-outbound-gateway>
JDBC锁注册处
4.3 版本引入了JdbcLock注册局.
某些组件(例如聚合器和重序器)使用由锁注册实例确保一次只有一个线程作一个组。
这默认锁注册表在单一组件内完成此功能。
你现在可以在这些组件上配置外部锁注册表。
与共享设备一起使用时MessageGroupStore,你可以使用JdbcLock注册局以便在多个应用实例之间提供此功能,使得一次只有一个实例能够作该组。
当本地线程释放锁时,另一个本地线程通常可以立即获取该锁。 如果使用不同注册表实例的线程释放锁,获取锁可能需要长达100毫秒。
这JdbcLock注册局基于锁仓库抽象,具有默认锁定仓库实现。
数据库模式脚本位于org.springframework.integration.jdbc该包被分配给不同的RDBMS厂商。
例如,以下列表展示了锁表的H2 DDL:
CREATE TABLE INT_LOCK (
LOCK_KEY CHAR(36),
REGION VARCHAR(100),
CLIENT_ID CHAR(36),
CREATED_DATE TIMESTAMP NOT NULL,
constraint INT_LOCK_PK primary key (LOCK_KEY, REGION)
);
这INT_可以根据目标数据库设计需求进行修改。
因此,你必须使用前缀属性默认锁定仓库豆子的定义。
有时,某个应用程序已进入无法解除分布式锁并移除数据库中特定记录的状态。
为此,这些死锁可以在下一次锁定调用时被另一个应用终止。
这时间到生命(TTL)选项默认锁定仓库为此目的而提供。
你可能还想具体说明CLIENT_ID对于给定的锁默认锁定仓库实例。
如果是这样,你可以指定身份证与默认锁定仓库作为构造子参数。
从5.1.8版本开始,JdbcLock注册局可以配置为idleBetweenTries-一个期间在锁记录插入/更新执行之间进行睡眠。
默认情况下,它是100毫秒级,在某些环境中,非领导者会频繁污染与数据源的连接。
从5.4版本开始,可再生锁注册表接口已被引入并新增于JdbcLock注册局.
这renewLock()必须在锁定进程中调用方法,否则锁定进程将超过锁的寿命。
因此,寿命可以大幅缩短,部署也能迅速夺回失去的锁。
| 锁更新只能在当前线程持有锁时进行。 |
版本为5.5.6的字符串,JdbcLock注册局是自动清理 JdbcLock 缓存的支持JdbcLockRegistry.locks通过JdbcLockRegistry.setCacheCapacity().
更多信息请参见其JavaDocs。
6.0版本的字符串,默认锁定仓库可以由PlatformTransactionManager而不是依赖应用上下文中的主豆。
JDBC 元数据存储
5.0 版本引入了 JDBC元数据存储(参见元数据存储)实现。
你可以使用Jdbc元数据存储以维护应用重启后的元数据状态。
这元数据存储实现方式可配合以下适配器实现:
要配置这些适配器以使用Jdbc元数据存储,通过使用豆名 宣告春季豆元数据存储.
Feed 入站通道适配器和 feed inbound 通道适配器都会自动拾取并使用 声明Jdbc元数据存储,如下示例所示:
@Bean
public MetadataStore metadataStore(DataSource dataSource) {
return new JdbcMetadataStore(dataSource);
}
这org.springframework.integration.jdbc该软件包包含多个 RDMBS 厂商的数据库模式脚本。
例如,以下列表展示了元数据表的H2 DDL:
CREATE TABLE INT_METADATA_STORE (
METADATA_KEY VARCHAR(255) NOT NULL,
METADATA_VALUE VARCHAR(4000),
REGION VARCHAR(100) NOT NULL,
constraint INT_METADATA_STORE_PK primary key (METADATA_KEY, REGION)
);
你可以更改INT_前缀以匹配目标数据库设计需求。
你也可以配置Jdbc元数据存储使用自定义前缀。
这Jdbc元数据存储实现并发元数据存储这使得密钥能够可靠地在多个应用实例间共享,只有一个实例可以存储或修改键值。
所有这些作都是原子级的,得益于交易保证。
事务管理必须使用Jdbc元数据存储.
入站通道适配器可以附带对事务管理器在轮询器配置中。
与非事务性不同元数据存储实现,其中Jdbc元数据存储,该条目仅在事务提交后才出现在目标表中。
当发生回滚时,不会向INT_METADATA_STORE桌子。
自5.0.7版本起,你可以配置Jdbc元数据存储RDBMS 则是厂商专用的lock提示支持基于锁定的元数据存储查询选项。
默认情况下,它是更新如果目标数据库不支持行锁定功能,也可以配置空字符串。
请咨询你的提供商,获取具体和可能的提示选择用于在更新前锁定行的表达式。