Stored Procedures

在某些情况下,普通的 JDBC 支持是不够的。也许你处理遗留关系数据库模式,或者你必须进行复杂的数据处理,但最终你必须使用 stored procedures 或存储过程。自 Spring 集成 2.1 以来,我们提供了三个组件来执行存储过程或存储函数:

In certain situations, plain JDBC support is not sufficient. Maybe you deal with legacy relational database schemas or you have complex data processing needs, but, ultimately, you have to use stored procedures or stored functions. Since Spring Integration 2.1, we provide three components to execute stored procedures or stored functions:

  • Stored Procedures Inbound Channel Adapter

  • Stored Procedures Outbound Channel Adapter

  • Stored Procedures Outbound Gateway

Supported Databases

为了启用对存储过程和存储函数的调用,存储过程组件使用了 org.springframework.jdbc.core.simple.SimpleJdbcCall 类。因此,完全支持以下数据库执行存储过程:

In order to enable calls to stored procedures and stored functions, the stored procedure components use the org.springframework.jdbc.core.simple.SimpleJdbcCall class. Consequently, the following databases are fully supported for executing stored procedures:

  • Apache Derby

  • DB2

  • MySQL

  • Microsoft SQL Server

  • Oracle

  • PostgreSQL

  • Sybase

如果你想要执行存储函数,则以下数据库得到完全支持:

If you want to execute stored functions instead, the following databases are fully supported:

  • MySQL

  • Microsoft SQL Server

  • Oracle

  • PostgreSQL

即使你的特定数据库可能未得到完全支持,但你仍很有可能能够成功使用存储过程 Spring Integration 组件,只要你的 RDBMS 支持存储过程或存储函数即可。

Even though your particular database may not be fully supported, chances are that you can use the stored procedure Spring Integration components quite successfully anyway, provided your RDBMS supports stored procedures or stored functions.

事实上,一些提供的集成测试使用 H2 database。但是,全面地测试那些使用场景非常重要。

As a matter of fact, some provided integration tests use the H2 database. Nevertheless, it is very important to thoroughly test those usage scenarios.

Configuration

存储过程组件提供完全的 XML 名称空间支持,并且配置组件与前面讨论的通用 JDBC 组件类似。

The stored procedure components provide full XML Namespace support, and configuring the components is similar as for the general purpose JDBC components discussed earlier.

Common Configuration Attributes

所有存储过程组件共享特定的配置参数:

All stored procedure components share certain configuration parameters:

  • auto-startup: Lifecycle attribute signaling whether this component should be started during application context startup. It defaults to true. Optional.

  • data-source: Reference to a javax.sql.DataSource, which is used to access the database. Required.

  • id: Identifies the underlying Spring bean definition, which is an instance of either EventDrivenConsumer or PollingConsumer, depending on whether the outbound channel adapter’s channel attribute references a SubscribableChannel or a PollableChannel. Optional.

  • ignore-column-meta-data: For fully supported databases, the underlying SimpleJdbcCall class can automatically retrieve the parameter information for the stored procedure or stored function from the JDBC metadata.[.iokays-translated-e0108a220b1c1aa37ce9d45420dd3252] 但是,如果数据库不支持元数据查找或如果你需要提供自定义参数定义,则可以将此标志设置成 true。它默认为 false。可选的。

However, if the database does not support metadata lookups or if you need to provide customized parameter definitions, this flag can be set to true. It defaults to false. Optional. * is-function: If true, a SQL Function is called. In that case, the stored-procedure-name or stored-procedure-name-expression attributes define the name of the called function. It defaults to false. Optional. * stored-procedure-name: This attribute specifies the name of the stored procedure. If the is-function attribute is set to true, this attribute specifies the function name instead. Either this property or stored-procedure-name-expression must be specified. * stored-procedure-name-expression: This attribute specifies the name of the stored procedure by using a SpEL expression. By using SpEL, you have access to the full message (if available), including its headers and payload. You can use this attribute to invoke different stored procedures at runtime. For example, you can provide stored procedure names that you would like to execute as a message header. The expression must resolve to a String.[.iokays-translated-839ab1ec539fcf9becf0bec8845613f5] 如果将 is-function 特性设置为 true,则此特性指定一个存储函数。此属性或 stored-procedure-name 必须指定。

If the is-function attribute is set to true, this attribute specifies a stored function. Either this property or stored-procedure-name must be specified. * jdbc-call-operations-cache-size: Defines the maximum number of cached SimpleJdbcCallOperations instances. Basically, for each stored procedure name, a new SimpleJdbcCallOperations instance is created that, in return, is cached.

Spring Integration 2.2 增加了 stored-procedure-name-expression 特性和 jdbc-call-operations-cache-size 特性。

Spring Integration 2.2 added the stored-procedure-name-expression attribute and the jdbc-call-operations-cache-size attribute.

默认缓存大小为 10。值为 0 将禁用缓存。不允许使用负值。

The default cache size is 10. A value of 0 disables caching. Negative values are not permitted.

如果您启用 JMX,则 {jdbc-call-operations-cache} 的统计信息将作为 MBean 暴露。有关更多信息,请参见 {MBean Exporter}。

If you enable JMX, statistical information about the jdbc-call-operations-cache is exposed as an MBean. See MBean Exporter for more information. * sql-parameter-source-factory: (Not available for the stored procedure inbound channel adapter.) Reference to a SqlParameterSourceFactory. By default, bean properties of the passed in Message payload are used as a source for the stored procedure’s input parameters by using a BeanPropertySqlParameterSourceFactory.[.iokays-translated-6f7f93e039494f215458b06dd54760c0] 这可能足以满足基本用例。对于更精细的选择,请考虑传入一个或多个 {ProcedureParameter} 值。有关详细信息,请参见 {Defining Parameter Sources}。可选。

This may suffice for basic use cases. For more sophisticated options, consider passing in one or more ProcedureParameter values. See Defining Parameter Sources. Optional. * use-payload-as-parameter-source: (Not available for the stored procedure inbound channel adapter.) If set to true, the payload of the Message is used as a source for providing parameters. If set to false, however, the entire Message is available as a source for parameters.[.iokays-translated-2e9cedf08f41b7e568d468c811c29e56] 如果没有传入存储过程参数,则此属性默认为 true。这意味着,通过使用默认的 BeanPropertySqlParameterSourceFactory,将使用有效负载的 bean 属性作为存储过程或存储函数的参数值的源。

If no procedure parameters are passed in, this property defaults to true. This means that, by using a default BeanPropertySqlParameterSourceFactory, the bean properties of the payload are used as a source for parameter values for the stored procedure or stored function.

但是,如果传入存储过程参数,此属性(默认情况下)将变为 falseProcedureParameter 让 SpEL 表达式得以提供。因此,非常有益于访问整个 Message。在底层的 StoredProcExecutor 上设置的属性。可选的。

However, if procedure parameters are passed in, this property (by default) evaluates to false. ProcedureParameter lets SpEL Expressions be provided. Therefore, it is highly beneficial to have access to the entire Message. The property set on the underlying StoredProcExecutor. Optional.

Common Configuration Sub-Elements

存储过程组件共享一组通用的子元素,你可以使用它们来定义参数并将其传递给存储过程或存储函数。有以下元素可用:

The stored procedure components share a common set of child elements that you can use to define and pass parameters to stored procedures or stored functions. The following elements are available:

  • parameter

  • returning-resultset

  • sql-parameter-definition

  • poller

  • parameter: Provides a mechanism to provide stored procedure parameters. Parameters can be either static or provided by using a SpEL Expressions.[source, xml]

<int-jdbc:parameter name=""         1
                    type=""         2
                    value=""/>      3

<int-jdbc:parameter name=""
                    expression=""/> 4
1 The name of the parameter to be passed into the Stored Procedure or Stored Function. Required.
2 This attribute specifies the type of the value. If nothing is provided, this attribute defaults to java.lang.String. This attribute is used only when the value attribute is used. Optional.
3 The value of the parameter. You must provide either this attribute or the expression attribute. Optional.
4 Instead of the value attribute, you can specify a SpEL expression for passing the value of the parameter. If you specify the expression, the value attribute is not allowed. Optional. Optional.
  • returning-resultset: Stored procedures may return multiple result sets. By setting one or more returning-resultset elements, you can specify RowMappers to convert each returned ResultSet to meaningful objects. Optional.[source, xml]

<int-jdbc:returning-resultset name="" row-mapper="" />
  • sql-parameter-definition: If you use a database that is fully supported, you typically do not have to specify the stored procedure parameter definitions. Instead, those parameters can be automatically derived from the JDBC metadata. However, if you use databases that are not fully supported, you must set those parameters explicitly by using the sql-parameter-definition element.[.iokays-translated-b56ef1f91ad14545092fa935fdbac026] 你还可以使用 ignore-column-meta-data 特性来选择关闭通过 JDBC 获得的任何参数元数据信息的处理。

You can also choose to turn off any processing of parameter metadata information obtained through JDBC by using the ignore-column-meta-data attribute.

<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 Specifies the name of the SQL parameter. Required.
2 Specifies the direction of the SQL parameter definition. Defaults to IN. Valid values are: IN, OUT, and INOUT. If your procedure is returning result sets, use the returning-resultset element. Optional.
3 The SQL type used for this SQL parameter definition. Translates into an integer value, as defined by java.sql.Types. Alternatively, you can provide the integer value as well. If this attribute is not explicitly set, it defaults to 'VARCHAR'. Optional.
4 The scale of the SQL parameter. Only used for numeric and decimal parameters. Optional.
5 The typeName for types that are user-named, such as: STRUCT, DISTINCT, JAVA_OBJECT, and named array types. This attribute is mutually exclusive with the scale attribute. Optional.
6 The reference to a custom value handler for complex types. An implementation of SqlReturnType. This attribute is mutually exclusive with the scale attribute and is only applicable for OUT and INOUT parameters. Optional.
  • poller: Lets you configure a message poller if this endpoint is a PollingConsumer. Optional.

Defining Parameter Sources

参数源控制获取 Spring Integration 消息属性并将其映射到相关存储过程输入参数的技术。

Parameter sources govern the techniques of retrieving and mapping the Spring Integration message properties to the relevant stored procedure input parameters.

存储过程组件遵循特定规则。默认情况下,Message 有效负载的 bean 属性被用作存储过程输入参数的源。在这种情况下,将使用 BeanPropertySqlParameterSourceFactory。这对于基本用例可能足够了。下一个示例说明了该默认行为。

The stored procedure components follow certain rules. By default, the bean properties of the Message payload are used as a source for the stored procedure’s input parameters. In that case, a BeanPropertySqlParameterSourceFactory is used. This may suffice for basic use cases. The next example illustrates that default behavior.

对于使用 BeanPropertySqlParameterSourceFactory 进行 “automatic” 查找 bean 特性,你的 bean 特性必须定义为小写。这是因为在 org.springframework.jdbc.core.metadata.CallMetaDataContext(Java 方法是 matchInParameterValuesWithCallParameters())中,检索的存储过程参数声明被转换为小写。因此,如果你有驼峰式 bean 特性(如 lastName),则查找将会失败。在这种情况下,提供一个明确的 ProcedureParameter

For the “automatic” lookup of bean properties by using the BeanPropertySqlParameterSourceFactory to work, your bean properties must be defined in lower case. This is due to the fact that in org.springframework.jdbc.core.metadata.CallMetaDataContext (the Java method is matchInParameterValuesWithCallParameters()), the retrieved stored procedure parameter declarations are converted to lower case. As a result, if you have camel-case bean properties (such as lastName), the lookup fails. In that case, provide an explicit ProcedureParameter.

假设我们有一个有效负载,它包含一个具有以下三个属性的简单 bean:idnamedescription。此外,我们有一个称为 INSERT_COFFEE 的简单存储过程,它接受三个输入参数:idnamedescription。我们还使用一个完全受支持的数据库。在这种情况下,对存储过程出站适配器进行以下配置就足够了:

Suppose we have a payload that consists of a simple bean with the following three properties: id, name, and description. Furthermore, we have a simplistic Stored Procedure called INSERT_COFFEE that accepts three input parameters: id, name, and description. We also use a fully supported database. In that case, the following configuration for a stored procedure outbound adapter suffices:

<int-jdbc:stored-proc-outbound-channel-adapter data-source="dataSource"
    channel="insertCoffeeProcedureRequestChannel"
    stored-procedure-name="INSERT_COFFEE"/>

对于更高级的选项,请考虑传入一个或多个 ProcedureParameter 值。

For more sophisticated options, consider passing in one or more ProcedureParameter values.

如果您确实显式提供了 ProcedureParameter 值,默认情况下会使用 ExpressionEvaluatingSqlParameterSourceFactory 用于参数处理,以支持 SpEL 表达式的全部功能。

If you do provide ProcedureParameter values explicitly, by default, an ExpressionEvaluatingSqlParameterSourceFactory is used for parameter processing, to enable the full power of SpEL expressions.

如果您需要进一步控制如何检索参数,请考虑使用 sql-parameter-source-factory 属性传入 SqlParameterSourceFactory 的自定义实现。

If you need even more control over how parameters are retrieved, consider passing in a custom implementation of SqlParameterSourceFactory by using the sql-parameter-source-factory attribute.

Stored Procedure Inbound Channel Adapter

以下列表调用对存储过程入站通道适配器重要的属性:

The following listing calls out the attributes that matter for a stored procedure inbound channel adapter:

<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 Channel to which polled messages are sent. If the stored procedure or function does not return any data, the payload of the Message is null. Required.
2 If this attribute is set to true, all results from a stored procedure call that do not have a corresponding SqlOutParameter declaration are bypassed. For example, stored procedures can return an update count value, even though your stored procedure declared only a single result parameter. The exact behavior depends on the database implementation. The value is set on the underlying JdbcTemplate. The value defaults to true. Optional.
3 Indicates whether this procedure’s return value should be included. Since Spring Integration 3.0. Optional.

Stored Procedure Outbound Channel Adapter

以下列表调用对存储过程出站通道适配器重要的属性:

The following listing calls out the attributes that matter for a stored procedure outbound channel adapter:

<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 The receiving message channel of this endpoint. Required.
2 Specifies the order for invocation when this endpoint is connected as a subscriber to a channel. This is particularly relevant when that channel is using a failover dispatching strategy. It has no effect when this endpoint is itself a polling consumer for a channel with a queue. Optional.

Stored Procedure Outbound Gateway

以下列表调用对存储过程出站通道适配器重要的属性:

The following listing calls out the attributes that matter for a stored procedure outbound channel adapter:

<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 The receiving message channel of this endpoint. Required.
2 Message channel to which replies should be sent after receiving the database response. Optional.
3 Lets you specify how long this gateway waits for the reply message to be sent successfully before throwing an exception. Keep in mind that, when sending to a DirectChannel, the invocation occurs in the sender’s thread. Consequently, the failing of the send operation may be caused by other components further downstream. The value is specified in milliseconds. Optional.
4 Indicates whether this procedure’s return value should be included. Optional.
5 If the skip-undeclared-results attribute is set to true, all results from a stored procedure call that do not have a corresponding SqlOutParameter declaration are bypassed. For example, stored procedures may return an update count value, even though your stored procedure only declared a single result parameter. The exact behavior depends on the database. The value is set on the underlying JdbcTemplate. The value defaults to true. Optional.

Examples

本节包含两个调用 { Apache Derby} 存储过程的示例。第一个过程调用了一个返回 {ResultSet} 的存储过程。通过使用 {RowMapper},数据被转化成一个域对象,然后成为 Spring Integration 消息有效负载。

This section contains two examples that call Apache Derby stored procedures. The first procedure calls a stored procedure that returns a ResultSet. By using a RowMapper, the data is converted into a domain object, which then becomes the Spring Integration message payload.

在第二个示例中,我们调用一个存储过程,该存储过程使用输出参数来返回数据。

In the second sample, we call a stored procedure that uses output parameters to return data instead.

该项目包含本文所引用的 Apache Derby 示例以及如何运行它的说明。Spring Integration Samples 项目还提供了一个如何使用 Oracle 存储过程的 { example}。

The project contains the Apache Derby example referenced here, as well as instructions on how to run it. The Spring Integration Samples project also provides an example of using Oracle stored procedures.

在第一个示例中,我们调用名为 FIND_ALL_COFFEE_BEVERAGES 的存储过程,该存储过程未定义任何输入参数,但返回 ResultSet

In the first example, we call a stored procedure named FIND_ALL_COFFEE_BEVERAGES that does not define any input parameters but that returns a ResultSet.

在 Apache Derby 中,存储过程在 Java 中实现。以下列表显示方法签名:

In Apache Derby, stored procedures are implemented in Java. The following listing shows the method signature:

public static void findAllCoffeeBeverages(ResultSet[] coffeeBeverages)
            throws SQLException {
    ...
}

以下列表显示相应的 SQL:

The following listing shows the corresponding 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 调用此存储过程,如下例所示:

In Spring Integration, you can now call this stored procedure by using, for example, a stored-proc-outbound-gateway, as the following example shows:

<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 的存储过程,该存储过程有一个输入参数。它不返回 ResultSet,而使用输出参数。以下示例显示方法签名:

In the second example, we call a stored procedure named FIND_COFFEE that has one input parameter. Instead of returning a ResultSet, it uses an output parameter. The following example shows the method signature:

public static void findCoffee(int coffeeId, String[] coffeeDescription)
            throws SQLException {
    ...
}

以下列表显示相应的 SQL:

The following listing shows the corresponding 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 调用此存储过程,如下例所示:

In Spring Integration, you can now call this Stored Procedure by using, for example, a stored-proc-outbound-gateway, as the following example shows:

<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>