存储过程
在某些情况下,普通的 JDBC 支持是不够的。 也许您处理的是旧式关系数据库架构,或者您有复杂的数据处理需求,但最终您必须使用存储过程或存储函数。 从 Spring Integration 2.1 开始,我们提供了三个组件来执行存储过程或存储函数:
-
存储过程入站通道适配器
-
存储过程出站通道适配器
-
存储过程出站网关
支持的数据库
为了启用对存储过程和存储函数的调用,存储过程组件使用org.springframework.jdbc.core.simple.SimpleJdbcCall
类。
因此,完全支持以下数据库执行存储过程:
-
阿帕奇德比
-
DB2
-
MySQL (MySQL的
-
Microsoft SQL 服务器
-
神谕
-
PostgreSQL 数据库
-
Sybase
如果您想改为执行存储函数,则完全支持以下数据库:
-
MySQL (MySQL的
-
Microsoft SQL 服务器
-
神谕
-
PostgreSQL 数据库
即使您的特定数据库可能没有得到完全支持,只要您的 RDBMS 支持存储过程或存储函数,您很可能可以非常成功地使用存储过程 Spring Integration 组件。 事实上,一些提供的集成测试使用 H2 数据库。 尽管如此,全面测试这些使用场景非常重要。 |
常见配置属性
所有存储过程组件共享某些配置参数:
-
auto-startup
:生命周期属性,指示是否应在应用程序上下文启动期间启动此组件。 它默认为 . 自选。true
-
data-source
:对 的引用,用于访问数据库。 必填。javax.sql.DataSource
-
id
:标识基础 Spring Bean 定义,它是 或 的实例,具体取决于出站通道适配器的属性是引用 a 还是 a 。 自选。EventDrivenConsumer
PollingConsumer
channel
SubscribableChannel
PollableChannel
-
ignore-column-meta-data
:对于完全支持的数据库,底层的SimpleJdbcCall
类可以从 JDBC 元数据中自动检索存储过程或存储函数的参数信息。但是,如果数据库不支持元数据查找,或者您需要提供自定义参数定义,则可以将此标志设置为 。 它默认为 . 自选。
true
false
-
is-function
:如果 ,则调用 SQL 函数。 在这种情况下,or 属性定义被调用函数的名称。 它默认为 . 自选。true
stored-procedure-name
stored-procedure-name-expression
false
-
stored-procedure-name
:此属性指定存储过程的名称。 如果该属性设置为 ,则此属性将指定函数名称。 此属性 或 必须指定。is-function
true
stored-procedure-name-expression
-
stored-procedure-name-expression
:此属性使用 SpEL 表达式指定存储过程的名称。 通过使用 SPEL,您可以访问完整的消息(如果可用),包括其 Headers 和有效负载。 您可以使用此属性在运行时调用不同的存储过程。 例如,您可以提供要作为消息标头执行的存储过程名称。 表达式必须解析为 .String
如果该属性设置为 ,则此属性指定存储函数。 此属性 或 必须指定。
is-function
true
stored-procedure-name
-
jdbc-call-operations-cache-size
:定义缓存实例的最大数量。 基本上,对于每个存储过程名称,都会创建一个新的SimpleJdbcCallOperations
实例,作为回报,该实例将被缓存。SimpleJdbcCallOperations
Spring Integration 2.2 添加了 attribute 和 attribute。 stored-procedure-name-expression
jdbc-call-operations-cache-size
默认缓存大小为 。 值 disable 缓存。 不允许使用负值。
10
0
如果启用 JMX,则有关 的统计信息将作为 MBean 公开。 有关更多信息,请参阅 MBean Exporter 。
jdbc-call-operations-cache
-
sql-parameter-source-factory
:(不适用于存储过程入站通道适配器。 对 . 默认情况下,传入的有效负载的 bean 属性通过使用 .SqlParameterSourceFactory
Message
BeanPropertySqlParameterSourceFactory
对于基本用例,这可能就足够了。 对于更复杂的选项,请考虑传入一个或多个值。 请参阅定义参数源。 自选。
ProcedureParameter
-
use-payload-as-parameter-source
:(不适用于存储过程入站通道适配器。 如果设置为 ,则 的有效负载将用作提供参数的源。 但是,如果设置为 ,则 entire 可用作参数的源。true
Message
false
Message
如果未传入任何过程参数,则此属性默认为 。 这意味着,通过使用 default ,有效负载的 bean 属性将用作存储过程或存储函数的参数值的源。
true
BeanPropertySqlParameterSourceFactory
但是,如果传入了过程参数,则此属性(默认情况下)的计算结果为 . 允许提供 SpEL 表达式。 因此,访问整个 . 在基础 . 自选。
false
ProcedureParameter
Message
StoredProcExecutor
常见配置子元素
存储过程组件共享一组通用的子元素,您可以使用这些子元素来定义参数并将其传递给存储过程或存储函数。 以下元素可用:
-
parameter
-
returning-resultset
-
sql-parameter-definition
-
poller
-
parameter
:提供存储过程参数的机制。 参数可以是静态的,也可以是使用 SPEL 表达式提供的。<int-jdbc:parameter name="" (1) type="" (2) value=""/> (3) <int-jdbc:parameter name="" expression=""/> (4)
1 要传递到 Stored Procedure 或 Stored Function 的参数的名称。 必填。 2 此属性指定值的类型。 如果未提供任何内容,则此属性默认为 . 仅当使用该属性时,才使用此属性。 自选。 java.lang.String
value
3 参数的值。 您必须提供此属性或属性。 自选。 expression
4 您可以指定 SPEL 表达式来传递参数的值,而不是属性。 如果指定 ,则不允许使用该属性。 自选。 自选。 value
expression
value
-
returning-resultset
:存储过程可能会返回多个结果集。 通过设置一个或多个元素,您可以指定将每个返回的对象转换为有意义的对象。 自选。returning-resultset
RowMappers
ResultSet
<int-jdbc:returning-resultset name="" row-mapper="" />
-
sql-parameter-definition
:如果使用完全支持的数据库,则通常不必指定存储过程参数定义。 相反,这些参数可以自动从 JDBC 元数据派生。 但是,如果您使用的数据库不完全受支持,则必须使用 element 显式设置这些参数。sql-parameter-definition
您还可以使用该属性选择关闭对通过 JDBC 获取的参数元数据信息的任何处理。
ignore-column-meta-data
<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 参数定义的方向。
默认为 。
有效值为: 、 和 。
如果过程返回结果集,请使用 element.
自选。IN IN OUT INOUT returning-resultset |
3 | 用于此 SQL 参数定义的 SQL 类型。
转换为整数值,如 定义。
或者,您也可以提供整数值。
如果未明确设置此属性,则默认为 'VARCHAR'。
自选。java.sql.Types |
4 | SQL 参数的比例。 仅用于数字和十进制参数。 自选。 |
5 | for 用户命名的类型,例如: 、 、 和 named 数组类型。
此属性与该属性互斥。
自选。typeName STRUCT DISTINCT JAVA_OBJECT scale |
6 | 对复杂类型的自定义值处理程序的引用。
SqlReturnType 的实现。
此属性与该属性互斥,仅适用于 OUT 和 INOUT 参数。
自选。scale
|
定义参数源
参数源控制检索 Spring 集成消息属性并将其映射到相关存储过程输入参数的技术。
存储过程组件遵循某些规则。
默认情况下,有效负载的 Bean 属性用作存储过程的 Importing 参数的源。
在这种情况下,使用 a。
对于基本用例,这可能就足够了。
下一个示例说明了该默认行为。Message
BeanPropertySqlParameterSourceFactory
要使用 to 工作对 bean 属性进行“自动”查找,必须以小写形式定义 bean 属性。
这是因为 in (Java 方法是 ),检索到的存储过程参数声明将转换为小写。
因此,如果您具有驼峰式大小写的 bean 属性(例如 ),则查找将失败。
在这种情况下,请提供显式 .BeanPropertySqlParameterSourceFactory org.springframework.jdbc.core.metadata.CallMetaDataContext matchInParameterValuesWithCallParameters() lastName ProcedureParameter |
假设我们有一个有效负载,它由一个具有以下三个属性的简单 bean 组成:、 和 。
此外,我们有一个简单的 Stored Procedure,它接受三个输入参数:、 和 。
我们还使用完全支持的数据库。
在这种情况下,存储过程出站适配器的以下配置就足够了:id
name
description
INSERT_COFFEE
id
name
description
<int-jdbc:stored-proc-outbound-channel-adapter data-source="dataSource"
channel="insertCoffeeProcedureRequestChannel"
stored-procedure-name="INSERT_COFFEE"/>
对于更复杂的选项,请考虑传入一个或多个值。ProcedureParameter
如果您确实显式提供了值,则默认情况下,an 用于参数处理,以启用 SPEL 表达式的全部功能。ProcedureParameter
ExpressionEvaluatingSqlParameterSourceFactory
如果需要对参数的检索方式进行更多控制,请考虑使用 attribute 传入 的自定义实现。SqlParameterSourceFactory
sql-parameter-source-factory
存储过程入站通道适配器
下面的清单列出了对存储过程入站通道适配器很重要的属性:
<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 | 轮询消息发送到的通道。
如果存储过程或函数未返回任何数据,则 的有效负载为 null。
必填。Message |
2 | 如果此属性设置为 ,则绕过存储过程调用中没有相应声明的所有结果。
例如,存储过程可以返回更新计数值,即使存储过程仅声明一个 result 参数。
确切的行为取决于数据库实现。
该值在基础 上设置。
该值默认为 。
自选。true SqlOutParameter JdbcTemplate true |
3 | 指示是否应包含此过程的返回值。 从 Spring Integration 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 | 指定此终端节点作为订阅者连接到通道时的调用顺序。
当该通道使用 dispatching 策略时,这一点尤其重要。
当此终端节点本身是具有队列的通道的轮询使用者时,它不起作用。
自选。failover |
存储过程出站网关
下面的清单列出了对存储过程出站通道适配器很重要的属性:
<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 | 允许您指定此网关在引发异常之前等待成功发送回复消息的时间。
请记住,当发送到 时,调用发生在发送方的线程中。
因此,send 操作的失败可能是由下游的其他组件引起的。
该值以毫秒为单位指定。
自选。DirectChannel |
4 | 指示是否应包含此过程的返回值。 自选。 |
5 | 如果该属性设置为 ,则绕过存储过程调用中没有相应声明的所有结果。
例如,存储过程可能会返回更新计数值,即使存储过程只声明了一个 result 参数。
确切的行为取决于数据库。
该值在基础 上设置。
该值默认为 。
自选。skip-undeclared-results true SqlOutParameter JdbcTemplate true |
例子
本节包含两个调用 Apache Derby 存储过程的示例。
第一个过程调用返回 .
通过使用 ,数据被转换为域对象,然后成为 Spring 集成消息有效负载。ResultSet
RowMapper
在第二个示例中,我们调用了一个存储过程,该过程使用输出参数来返回数据。
该项目包含此处引用的 Apache Derby 示例,以及有关如何运行它的说明。 Spring Integration Samples 项目还提供了一个使用 Oracle 存储过程的示例。 |
在第一个示例中,我们调用一个名为 的存储过程,该过程未定义任何输入参数,但返回一个 .FIND_ALL_COFFEE_BEVERAGES
ResultSet
在 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 集成中,您现在可以使用例如a来调用此存储过程,如下例所示: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>
在第二个示例中,我们调用了一个名为 的存储过程,该存储过程具有一个输入参数。
它使用 output 参数,而不是返回 。
以下示例显示了方法签名:FIND_COFFEE
ResultSet
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 集成中,您现在可以通过使用例如a来调用此存储过程,如下例所示: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>