ストアドプロシージャー

特定の状況では、プレーンな JDBC サポートでは不十分です。おそらく、従来のリレーショナルデータベーススキーマを扱うか、複雑なデータ処理のニーズがありますが、最終的には、ストアドプロシージャ [Wikipedia] (英語) またはストアドファンクションを使用する必要があります。Spring Integration 2.1 以降、ストアドプロシージャまたはストアドファンクションを実行する 3 つのコンポーネントを提供しています。

  • ストアドプロシージャの受信チャネルアダプター

  • ストアドプロシージャの送信チャネルアダプター

  • ストアドプロシージャの送信ゲートウェイ

サポートされているデータベース

ストアドプロシージャとストアドファンクションの呼び出しを可能にするために、ストアドプロシージャコンポーネントは org.springframework.jdbc.core.simple.SimpleJdbcCall (Javadoc) クラスを使用します。ストアドプロシージャの実行では、次のデータベースが完全にサポートされています。

  • Apache Derby

  • DB2

  • MySQL

  • Microsoft SQL Server

  • Oracle

  • PostgreSQL

  • Sybase

代わりにストアド関数を実行する場合、次のデータベースが完全にサポートされます。

  • MySQL

  • Microsoft SQL Server

  • Oracle

  • PostgreSQL

特定のデータベースが完全にサポートされていない場合でも、RDBMS がストアドプロシージャまたはストアド関数をサポートしていれば、ストアドプロシージャ Spring Integration コンポーネントを非常にうまく使用できる可能性があります。

実際のところ、提供されている統合テストの中には H2 データベース (英語) を使用しているものがあります。それでも、これらの使用シナリオを徹底的にテストすることは非常に重要です。

構成

ストアドプロシージャコンポーネントは、XML 名前空間を完全にサポートします。コンポーネントの構成は、前述の汎用 JDBC コンポーネントと同様です。

共通の構成属性

すべてのストアドプロシージャコンポーネントは、特定の構成パラメーターを共有します。

  • auto-startup: アプリケーションコンテキストの起動時にこのコンポーネントを起動する必要があるかどうかを示すライフサイクル属性。デフォルトは true です。オプション。

  • data-source: データベースへのアクセスに使用される javax.sql.DataSource への参照。必須。

  • id: 発信チャネルアダプターの channel 属性が SubscribableChannel または PollableChannel のどちらを参照するかに応じて、基になる Spring Bean 定義を識別します。これは、EventDrivenConsumer または PollingConsumer のいずれかのインスタンスです。オプション。

  • ignore-column-meta-data: 完全にサポートされているデータベースの場合、基になる SimpleJdbcCall (Javadoc) クラスは、JDBC メタデータからストアドプロシージャまたはストアドファンクションのパラメーター情報を自動的に取得できます。

    ただし、データベースがメタデータ検索をサポートしていない場合、またはカスタマイズされたパラメーター定義を提供する必要がある場合、このフラグを true に設定できます。デフォルトは false です。オプション。

  • is-functiontrue の場合、SQL 関数が呼び出されます。その場合、stored-procedure-name または stored-procedure-name-expression 属性は、呼び出された関数の名前を定義します。デフォルトは false です。オプション。

  • stored-procedure-name: この属性は、ストアドプロシージャの名前を指定します。is-function 属性が true に設定されている場合、この属性は代わりに関数名を指定します。このプロパティまたは stored-procedure-name-expression のいずれかを指定する必要があります。

  • stored-procedure-name-expression: この属性は、SpEL 式を使用してストアドプロシージャの名前を指定します。SpEL を使用すると、ヘッダーとペイロードを含む完全なメッセージ(利用可能な場合)にアクセスできます。この属性を使用して、実行時にさまざまなストアドプロシージャを呼び出すことができます。例: メッセージヘッダーとして実行するストアドプロシージャ名を指定できます。式は String に解決する必要があります。

    is-function 属性が true に設定されている場合、この属性はストアド関数を指定します。このプロパティまたは stored-procedure-name のいずれかを指定する必要があります。

  • jdbc-call-operations-cache-size: キャッシュされる SimpleJdbcCallOperations インスタンスの最大数を定義します。基本的に、ストアドプロシージャ名ごとに、新しい SimpleJdbcCallOperations (Javadoc) インスタンスが作成され、そのインスタンスがキャッシュされます。

    Spring Integration 2.2 は、stored-procedure-name-expression 属性と jdbc-call-operations-cache-size 属性を追加しました。

    デフォルトのキャッシュサイズは 10 です。0 の値はキャッシュを無効にします。負の値は許可されていません。

    JMX を有効にすると、jdbc-call-operations-cache に関する統計情報が MBean として公開されます。詳細については、MBean エクスポーターを参照してください。

  • sql-parameter-source-factory: (ストアードプロシージャーの受信・チャネルアダプターには使用できません) SqlParameterSourceFactory への参照。デフォルトでは、渡された Message ペイロードの Bean プロパティは、BeanPropertySqlParameterSourceFactory を使用して、ストアドプロシージャの入力パラメーターのソースとして使用されます。

    これは基本的な使用例で十分です。より高度なオプションについては、1 つ以上の ProcedureParameter 値を渡すことを検討してください。パラメーターソースの定義を参照してください。オプション。

  • use-payload-as-parameter-source: (ストアードプロシージャーの受信・チャネルアダプターでは使用できません) true に設定されている場合、Message のペイロードはパラメーターを提供するためのソースとして使用されます。ただし、false に設定すると、Message 全体がパラメーターのソースとして使用可能になります。

    プロシージャパラメーターが渡されない場合、このプロパティのデフォルトは true になります。これは、デフォルトの BeanPropertySqlParameterSourceFactory を使用することにより、ペイロードの Bean プロパティがストアドプロシージャまたはストアドファンクションのパラメーター値のソースとして使用されることを意味します。

    ただし、プロシージャパラメーターが渡された場合、このプロパティは (デフォルトで) false と評価されます。ProcedureParameter では SpEL 式を提供できます。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 ストアドプロシージャまたはストアド関数に渡されるパラメーターの名前。必須。
    2 この属性は値の型を指定します。何も指定しない場合、この属性はデフォルトで java.lang.String になります。この属性は、value 属性が使用されている場合にのみ使用されます。オプション。
    3 パラメーターの値。この属性または expression 属性のいずれかを指定する必要があります。オプション。
    4value 属性の代わりに、パラメーターの値を渡すための SpEL 式を指定できます。expression を指定した場合、value 属性は許可されません。オプション。オプション。
  • returning-resultset: ストアドプロシージャは複数の結果セットを返す場合があります。1 つ以上の returning-resultset 要素を設定することにより、RowMappers を指定して、返された各 ResultSet を意味のあるオブジェクトに変換できます。オプション。

    <int-jdbc:returning-resultset name="" row-mapper="" />
  • sql-parameter-definition: 完全にサポートされているデータベースを使用する場合、通常、ストアドプロシージャのパラメーター定義を指定する必要はありません。代わりに、これらのパラメーターは JDBC メタデータから自動的に派生できます。ただし、完全にサポートされていないデータベースを使用する場合は、sql-parameter-definition 要素を使用してこれらのパラメーターを明示的に設定する必要があります。

    ignore-column-meta-data 属性を使用して、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)
1SQL パラメーターの名前を指定します。必須。
2SQL パラメーター定義の方向を指定します。デフォルトは IN です。有効な値は次のとおりです: INOUTINOUT。プロシージャが結果セットを返す場合は、returning-resultset 要素を使用してください。オプション。
3 この SQL パラメーター定義に使用される SQL 型。java.sql.Types で定義されている整数値に変換します。または、整数値も提供できます。この属性が明示的に設定されていない場合、デフォルトは "VARCHAR" です。オプション。
4SQL パラメーターのスケール。数値および小数のパラメーターにのみ使用されます。オプション。
5STRUCTDISTINCTJAVA_OBJECT などのユーザー指定の型および名前付き配列型の typeName。この属性は、scale 属性と相互に排他的です。オプション。
6 複合型のカスタム値ハンドラーへの参照。SqlReturnType (Javadoc) の実装。この属性は scale 属性と相互に排他的であり、OUT および INOUT パラメーターにのみ適用可能です。オプション。
  • poller: このエンドポイントが PollingConsumer の場合、メッセージポーラーを構成できます。オプション。

パラメーターソースの定義

パラメーターソースは、Spring Integration メッセージプロパティを取得し、関連するストアドプロシージャの入力パラメーターにマッピングする手法を管理します。

ストアドプロシージャコンポーネントは、特定の規則に従います。デフォルトでは、Message ペイロードの Bean プロパティは、ストアドプロシージャの入力パラメーターのソースとして使用されます。その場合、BeanPropertySqlParameterSourceFactory が使用されます。これは基本的な使用例で十分です。次の例は、デフォルトの動作を示しています。

BeanPropertySqlParameterSourceFactory を使用した Bean プロパティの「自動」ルックアップを機能させるには、Bean プロパティを小文字で定義する必要があります。これは、org.springframework.jdbc.core.metadata.CallMetaDataContext (Java メソッドは matchInParameterValuesWithCallParameters())では、取得されたストアドプロシージャのパラメーター宣言が小文字に変換されるためです。その結果、キャメルケース Bean プロパティ(lastName など)がある場合、検索は失敗します。その場合、明示的な ProcedureParameter を提供します。

次の 3 つのプロパティを持つ単純な Bean で構成されるペイロードがあるとします: idnamedescription。さらに、idnamedescription という 3 つの入力パラメーターを受け入れる INSERT_COFFEE と呼ばれる単純なストアドプロシージャがあります。また、完全にサポートされているデータベースを使用しています。その場合、ストアードプロシージャーの送信・アダプターの以下の構成で十分です。

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

より高度なオプションについては、1 つ以上の ProcedureParameter 値を渡すことを検討してください。

ProcedureParameter 値を明示的に指定した場合、デフォルトでは、ExpressionEvaluatingSqlParameterSourceFactory がパラメーター処理に使用され、SpEL 式のフルパワーが有効になります。

パラメーターの取得方法をさらに制御する必要がある場合は、sql-parameter-source-factory 属性を使用して SqlParameterSourceFactory のカスタム実装を渡すことを検討してください。

ストアドプロシージャ受信チャネルアダプター

次のリストは、ストアドプロシージャ受信チャネルアダプターに関係する属性を示しています。

<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 ポーリングされたメッセージが送信されるチャネル。ストアドプロシージャまたは関数がデータを返さない場合、Message のペイロードは null です。必須。
2 この属性が 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 このエンドポイントがチャンネルのサブスクライバーとして接続されている場合の呼び出しの順序を指定します。これは、そのチャネルが 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 このゲートウェイが例外をスローする前に応答メッセージが正常に送信されるまで待機する時間を指定できます。DirectChannel に送信する場合、呼び出しは送信者のスレッドで発生することに注意してください。送信操作の失敗は、さらに下流の他のコンポーネントによって引き起こされる可能性があります。値はミリ秒単位で指定します。オプション。
4 このプロシージャの戻り値を含めるかどうかを示します。オプション。
5skip-undeclared-results 属性が true に設定されている場合、対応する SqlOutParameter 宣言を持たないストアドプロシージャコールの結果はすべてバイパスされます。例: ストアドプロシージャが単一の結果パラメーターのみを宣言している場合でも、ストアドプロシージャは更新カウント値を返すことがあります。正確な動作はデータベースによって異なります。値は、基礎となる JdbcTemplate に設定されます。値のデフォルトは true です。オプション。

サンプル

このセクションには、Apache Derby (英語) ストアドプロシージャを呼び出す 2 つの例が含まれています。最初のプロシージャは、ResultSet を返すストアドプロシージャを呼び出します。RowMapper を使用することにより、データはドメインオブジェクトに変換され、その後、Spring Integration メッセージペイロードになります。

2 番目のサンプルでは、代わりに出力パラメーターを使用してデータを返すストアドプロシージャを呼び出します。

プロジェクトには、ここで参照されている Apache Derby の例と、その実行メソッドの説明が含まれています。Spring Integration サンプルプロジェクトには、Oracle ストアドプロシージャの使用例 [GitHub] (英語) も用意されています。

最初の例では、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 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>

2 番目の例では、1 つの入力パラメーターを持つ 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 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>