JPA サポート
Spring Integration の JPA(Java Persistence API)モジュールは、JPA を使用してさまざまなデータベース操作を実行するためのコンポーネントを提供します。
この依存関係をプロジェクトに含める必要があります。
JPA API は、ベンダー固有の実装を介して含める必要があります。Hibernate ORM フレームワーク。
次のコンポーネントが提供されます。
これらのコンポーネントを使用して、ターゲットデータベースとメッセージを送受信することにより、ターゲットデータベースで select、create、update、delete 操作を実行できます。
JPA 受信チャネルアダプターでは、JPA を使用してデータベースからデータをポーリングおよび取得(select)できますが、JPA 送信チャネルアダプターではエンティティを作成、更新、削除できます。
JPA の送信ゲートウェイを使用して、エンティティをデータベースに保持し、フローを継続し、ダウンストリームでさらにコンポーネントを実行できます。同様に、送信ゲートウェイを使用して、データベースからエンティティを取得できます。
例: 送信ゲートウェイを使用して、userId を含む Message をリクエストチャネルでペイロードとして受信し、データベースを照会してユーザーエンティティを取得し、さらに処理するためにダウンストリームに渡すことができます。
これらのセマンティックの違いを認識して、Spring Integration は 2 つの別個の JPA 送信ゲートウェイを提供します。
送信ゲートウェイの取得
送信ゲートウェイの更新
機能性
すべての JPA コンポーネントは、次のいずれかを使用して、それぞれの JPA 操作を実行します。
エンティティクラス
更新、選択、削除のための Java Persistence Query Language(JPQL) (JPQL は挿入をサポートしていません)
ネイティブクエリ
名前付きクエリ
次のセクションでは、これらの各コンポーネントについて詳しく説明します。
サポートされている永続性プロバイダー
Spring Integration JPA サポートは、次の永続性プロバイダーに対してテストされています。
Hibernate
EclipseLink
永続性プロバイダーを使用する場合、プロバイダーが JPA 2.1 と互換性があることを確認する必要があります。
Java 実装
提供されている各コンポーネントは o.s.i.jpa.core.JpaExecutor クラスを使用し、このクラスは o.s.i.jpa.core.JpaOperations インターフェースの実装を使用します。JpaOperations は一般的なデータアクセスオブジェクト (DAO) のように動作し、find、persist、executeUpdate などのメソッドを提供します。ほとんどのユースケースでは、既定の実装 (o.s.i.jpa.core.DefaultJpaOperations) で十分です。ただし、カスタム動作が必要な場合は、独自の実装を指定できます。
JpaExecutor を初期化するには、次のいずれかを受け入れるコンストラクターのいずれかを使用する必要があります。
EntityManagerFactory
EntityManager
JpaOperations
次の例は、JpaExecutor を entityManagerFactory で初期化し、送信ゲートウェイで使用する方法を示しています。
@Bean
public JpaExecutor jpaExecutor() {
JpaExecutor executor = new JpaExecutor(this.entityManagerFactory);
executor.setJpaParameters(Collections.singletonList(new JpaParameter("firstName", null, "#this")));
executor.setUsePayloadAsParameterSource(true);
executor.setExpectSingleResult(true);
return executor;
}
@ServiceActivator(inputChannel = "getEntityChannel")
@Bean
public MessageHandler retrievingJpaGateway() {
JpaOutboundGateway gateway = new JpaOutboundGateway(jpaExecutor());
gateway.setGatewayType(OutboundGatewayType.RETRIEVING);
gateway.setOutputChannelName("resultsChannel");
return gateway;
}名前空間サポート
XML 名前空間サポートを使用する場合、基礎となるパーサークラスが関連する Java クラスをインスタンス化します。通常、JPA アダプターの内部動作を処理する必要はありません。このセクションでは、Spring Integration が提供する XML 名前空間サポートについて説明し、XML 名前空間サポートを使用して JPA コンポーネントを構成する方法を示します。
共通の XML 名前空間設定属性
特定の構成パラメーターは、すべての JPA コンポーネントで共有されます。
auto-startupアプリケーションコンテキストの起動中にこのコンポーネントを起動する必要があるかどうかを通知するライフサイクル属性。デフォルトは
trueです。オプション。id基になる Spring Bean 定義を識別します。これは、
EventDrivenConsumerまたはPollingConsumerのいずれかのインスタンスです。オプション。entity-manager-factoryアダプターが
EntityManagerを作成するために使用する JPA エンティティマネージャーファクトリへの参照。この属性、entity-manager属性、jpa-operations属性を提供する必要があります。entity-managerコンポーネントが使用する JPA Entity Manager への参照。この属性、
entity-manager-factory属性、jpa-operations属性を提供する必要があります。通常、Spring アプリケーションコンテキストは JPA エンティティマネージャーファクトリのみを定義し、 EntityManagerは@PersistenceContextアノテーションを使用して挿入されます。このアプローチは、Spring Integration JPA コンポーネントには適用されません。通常、JPA エンティティマネージャーファクトリを注入するのが最適ですが、EntityManagerを明示的に注入する場合は、SharedEntityManagerBeanを定義する必要があります。詳細については、関連する Javadoc を参照してください。次の例は、エンティティマネージャーファクトリを明示的に含める方法を示しています。
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean"> <property name="entityManagerFactory" ref="entityManagerFactoryBean" /> </bean>jpa-operationsJpaOperationsインターフェースを実装する Bean への参照。まれに、デフォルトの実装(org.springframework.integration.jpa.core.DefaultJpaOperations)に頼るのではなく、JpaOperationsインターフェースの独自の実装を提供することをお勧めします。jpa-operations属性を使用する場合、JpaOperationsは必要なデータソースをラップするため、JPA エンティティマネージャーまたは JPA エンティティマネージャーファクトリを提供しないでください。entity-classエンティティクラスの完全修飾名。この属性の正確なセマンティクスは、永続化または更新操作を実行しているか、データベースからオブジェクトを取得しているかによって異なります。
データを取得するときに、
entity-class属性を指定して、データベースからこの型のオブジェクトを取得することを示すことができます。その場合、クエリ属性(jpa-query、native-query、named-query)を定義しないでください。データを永続化する場合、
entity-class属性は永続化するオブジェクトの型を示します。指定しない場合(永続化操作の場合)、エンティティクラスはメッセージのペイロードから自動的に取得されます。jpa-query使用する JPA クエリ(Java Persistence Query Language)を定義します。
native-query使用するネイティブ SQL クエリを定義します。
named-query名前付きクエリを参照します。名前付きクエリは、ネイティブ SQL または JPAQL のいずれかで定義できますが、基礎となる JPA 永続性プロバイダーがその区別を内部的に処理します。
JPA クエリパラメーターの提供
パラメーターを提供するには、parameter XML エレメントを使用できます。Java Persistence Query Language(JPQL)またはネイティブ SQL クエリのいずれかに基づくクエリのパラメーターを提供できるメカニズムがあります。名前付きクエリのパラメーターを提供することもできます。
- 式ベースのパラメーター
次の例は、式ベースのパラメーターを設定する方法を示しています。
<int-jpa:parameter expression="payload.name" name="firstName"/>- 値ベースのパラメーター
次の例は、値ベースのパラメーターを設定する方法を示しています。
<int-jpa:parameter name="name" type="java.lang.String" value="myName"/>- 位置パラメーター
次の例は、式ベースのパラメーターを設定する方法を示しています。
<int-jpa:parameter expression="payload.name"/> <int-jpa:parameter type="java.lang.Integer" value="21"/>
トランザクション処理
すべての JPA 操作(INSERT、UPDATE、DELETE など)は、実行されるたびにトランザクションがアクティブである必要があります。受信チャネルアダプターの場合、特別なことは何もする必要はありません。これは、他の受信チャネルアダプターで使用されるポーラーを使用してトランザクションマネージャーを構成する方法と同様に機能します。次の XML の例では、受信チャネルアダプターでポーラーを使用するトランザクションマネージャーを構成します。
<int-jpa:inbound-channel-adapter
channel="inboundChannelAdapterOne"
entity-manager="em"
auto-startup="true"
jpa-query="select s from Student s"
expect-single-result="true"
delete-after-poll="true">
<int:poller fixed-rate="2000" >
<int:transactional propagation="REQUIRED"
transaction-manager="transactionManager"/>
</int:poller>
</int-jpa:inbound-channel-adapter> ただし、送信チャネルアダプターまたはゲートウェイを使用する場合は、特にトランザクションを開始する必要があります。DirectChannel が送信アダプターまたはゲートウェイの入力チャネルであり、トランザクションが現在の実行スレッドでアクティブな場合、JPA 操作は同じトランザクションコンテキストで実行されます。次の例に示すように、この JPA 操作を新しいトランザクションとして実行するように構成することもできます。
<int-jpa:outbound-gateway
request-channel="namedQueryRequestChannel"
reply-channel="namedQueryResponseChannel"
named-query="updateStudentByRollNumber"
entity-manager="em"
gateway-type="UPDATING">
<int-jpa:parameter name="lastName" expression="payload"/>
<int-jpa:parameter name="rollNumber" expression="headers['rollNumber']"/>
<int-jpa:transactional propagation="REQUIRES_NEW"
transaction-manager="transactionManager"/>
</int-jpa:outbound-gateway> 前の例では、送信ゲートウェイまたはアダプターのトランザクション要素がトランザクション属性を指定しています。DirectChannel をアダプターへの入力チャネルとして使用し、呼び出し元と同じトランザクションコンテキストでアダプターに操作を実行させる場合、この子要素を定義することはオプションです。ただし、ExecutorChannel を使用する場合は、呼び出しクライアントのトランザクションコンテキストが伝播されないため、transactional 要素が必要です。
Spring Integration の名前空間で定義されているポーラーの transactional 要素とは異なり、発信ゲートウェイまたはアダプターの transactional 要素は JPA 名前空間で定義されています。 |
受信チャネルアダプター
受信チャネルアダプターを使用して、JPA QL を使用してデータベースに対して選択クエリを実行し、結果を返します。メッセージのペイロードは、単一のエンティティまたはエンティティの List のいずれかです。次の XML は inbound-channel-adapter を構成します。
<int-jpa:inbound-channel-adapter channel="inboundChannelAdapterOne" (1)
entity-manager="em" (2)
auto-startup="true" (3)
query="select s from Student s" (4)
expect-single-result="true" (5)
max-results="" (6)
max-results-expression="" (7)
delete-after-poll="true" (8)
flush-after-delete="true"> (9)
<int:poller fixed-rate="2000" >
<int:transactional propagation="REQUIRED" transaction-manager="transactionManager"/>
</int:poller>
</int-jpa:inbound-channel-adapter>| 1 | query 属性で JPA QL を実行した後、inbound-channel-adapter がメッセージ(ペイロードを含む)を置くチャネル。 |
| 2 | 必要な JPA 操作の実行に使用される EntityManager インスタンス。 |
| 3 | アプリケーションコンテキストの起動時にコンポーネントが自動的に起動するかどうかを示す属性。値のデフォルトは true です。 |
| 4 | 結果がメッセージのペイロードとして送信される JPA QL |
| 5 | この属性は、JPQL クエリが結果で単一のエンティティを提供するか、エンティティの List を提供するかを示します。値が true に設定されている場合、単一のエンティティがメッセージのペイロードとして送信されます。ただし、これを true に設定した後に複数の結果が返される場合、MessagingException がスローされます。値のデフォルトは false です。 |
| 6 | この非ゼロ、非負の整数値は、選択操作の実行時に、指定された行数を超える行を選択しないようアダプターに指示します。デフォルトでは、この属性が設定されていない場合、すべての可能なレコードがクエリによって選択されます。この属性は max-results-expression と相互に排他的です。オプション。 |
| 7 | 結果セット内の結果の最大数を見つけるために評価される式。max-results と相互に排他的。オプション。 |
| 8 | クエリの実行後に受信した行を削除する場合は、この値を true に設定します。コンポーネントがトランザクションの一部として動作することを確認する必要があります。そうしないと、次のような例外が発生する可能性があります。java.lang.IllegalArgumentException: Removing a detached instance … |
| 9 | 受信したエンティティを削除した直後に永続コンテキストをフラッシュする場合、および EntityManager の flushMode に依存したくない場合は、この値を true に設定します。値のデフォルトは false です。 |
構成パラメーターのリファレンス
次のリストは、inbound-channel-adapter に設定できるすべての値を示しています。
<int-jpa:inbound-channel-adapter
auto-startup="true" (1)
channel="" (2)
delete-after-poll="false" (3)
delete-per-row="false" (4)
entity-class="" (5)
entity-manager="" (6)
entity-manager-factory="" (7)
expect-single-result="false" (8)
id=""
jpa-operations="" (9)
jpa-query="" (10)
named-query="" (11)
native-query="" (12)
parameter-source="" (13)
send-timeout=""> (14)
<int:poller ref="myPoller"/>
</int-jpa:inbound-channel-adapter>| 1 | このライフサイクル属性は、アプリケーションコンテキストの起動時にこのコンポーネントが自動的に起動するかどうかを示します。この属性のデフォルトは true です。オプション。 |
| 2 | アダプターが、目的の JPA 操作の実行からのペイロードを含むメッセージを送信するチャネル。 |
| 3 | 選択されたレコードがアダプターによってポーリングされた後に削除するかどうかを示すブールフラグ。デフォルトでは、値は false です(つまり、レコードは削除されません)。コンポーネントがトランザクションの一部として動作することを確認する必要があります。そうしないと、java.lang.IllegalArgumentException: Removing a detached instance … などの例外が発生する場合があります。オプション。 |
| 4 | レコードを一括で削除できるか、一度に 1 レコードずつ削除する必要があるかを示すブールフラグ。デフォルトでは、値は false です(つまり、レコードを一括削除できます)。オプション。 |
| 5 | データベースから照会されるエンティティクラスの完全修飾名。アダプターは、エンティティクラス名に基づいて JPA クエリを自動的に構築します。オプション。 |
| 6 | JPA 操作の実行に使用される javax.persistence.EntityManager のインスタンス。オプション。 |
| 7 | JPA 操作を実行する javax.persistence.EntityManager のインスタンスを取得するために使用される javax.persistence.EntityManagerFactory のインスタンス。オプション。 |
| 8 | 選択操作が単一の結果を返すか、結果の List を返すかを示すブールフラグ。このフラグが true に設定されている場合、選択された単一のエンティティがメッセージのペイロードとして送信されます。複数のエンティティが返されると、例外がスローされます。false の場合、エンティティの List がメッセージのペイロードとして送信されます。値のデフォルトは false です。オプション。 |
| 9 | JPA 操作の実行に使用される org.springframework.integration.jpa.core.JpaOperations の実装。独自の実装を提供するのではなく、デフォルトの org.springframework.integration.jpa.core.DefaultJpaOperations 実装を使用することをお勧めします。entity-manager、entity-manager-factory、jpa-operations 属性のいずれかを使用できます。オプション。 |
| 10 | このアダプターによって実行される JPA QL。オプション。 |
| 11 | このアダプターで実行する必要がある名前付きクエリ。オプション。 |
| 12 | このアダプターによって実行されるネイティブクエリ。jpa-query、named-query、entity-class または native-query 属性のいずれかを使用できます。オプション。 |
| 13 | クエリのパラメーターの値を解決するために使用される o.s.i.jpa.support.parametersource.ParameterSource の実装。entity-class 属性に値がある場合は無視されます。オプション。 |
| 14 | チャネルにメッセージを送信するときに待機する最大時間(ミリ秒)。オプション。 |
Java 構成を使用した構成
次の Spring Boot アプリケーションは、Java で受信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public JpaExecutor jpaExecutor() {
JpaExecutor executor = new JpaExecutor(this.entityManagerFactory);
jpaExecutor.setJpaQuery("from Student");
return executor;
}
@Bean
@InboundChannelAdapter(channel = "jpaInputChannel",
poller = @Poller(fixedDelay = "${poller.interval}"))
public MessageSource<?> jpaInbound() {
return new JpaPollingChannelAdapter(jpaExecutor());
}
@Bean
@ServiceActivator(inputChannel = "jpaInputChannel")
public MessageHandler handler() {
return message -> System.out.println(message.getPayload());
}
}Java DSL を使用した構成
次の Spring Boot アプリケーションは、Java DSL で受信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public IntegrationFlow pollingAdapterFlow() {
return IntegrationFlows
.from(Jpa.inboundAdapter(this.entityManagerFactory)
.entityClass(StudentDomain.class)
.maxResults(1)
.expectSingleResult(true),
e -> e.poller(p -> p.trigger(new OnlyOnceTrigger())))
.channel(c -> c.queue("pollingResults"))
.get();
}
}送信チャネルアダプター
JPA 送信チャネルアダプターを使用すると、リクエストチャネルを介してメッセージを受け入れることができます。ペイロードは、永続化されるエンティティとして使用するか、JPQL クエリのパラメーター式のヘッダーで使用できます。次のセクションでは、これらの操作を実行する方法について説明します。
エンティティクラスの使用
次の XML は、エンティティをデータベースに永続化するように送信チャネルアダプターを構成します。
<int-jpa:outbound-channel-adapter channel="entityTypeChannel" (1)
entity-class="org.springframework.integration.jpa.test.entity.Student" (2)
persist-mode="PERSIST" (3)
entity-manager="em"/ > (4)| 1 | 有効な JPA エンティティが JPA 発信チャネルアダプターに送信されるチャネル。 |
| 2 | データベースに永続化するためにアダプターによって受け入れられるエンティティクラスの完全修飾名。アダプターは Spring Integration メッセージペイロードからエンティティクラスを自動的に決定できるため、ほとんどの場合、この属性は実際に省略できます。 |
| 3 | アダプターによって実行される操作。有効な値は PERSIST、MERGE、DELETE です。デフォルト値は MERGE です。 |
| 4 | 使用する JPA エンティティマネージャー。 |
outbound-channel-adapter のこれらの 4 つの属性は、入力チャネルを介してエンティティを受け入れ、基になるデータソースからエンティティを PERSIST、MERGE、DELETE に処理するように構成します。
Spring Integration 3.0 以降、PERSIST または MERGE へのペイロードも java.lang.Iterable (標準 Javadoc) (英語) 型にすることができます。その場合、Iterable によって返される各オブジェクトはエンティティとして扱われ、基になる EntityManager を使用して永続化またはマージされます。イテレータから返された null 値は無視されます。 |
JPA クエリ言語の使用 (JPA QL)
前のセクションでは、エンティティを使用して PERSIST アクションを実行する方法を示しました。このセクションでは、JPA QL で送信チャネルアダプターを使用する方法を示します。
次の XML は、エンティティをデータベースに永続化するように送信チャネルアダプターを構成します。
<int-jpa:outbound-channel-adapter channel="jpaQlChannel" (1)
jpa-query="update Student s set s.firstName = :firstName where s.rollNumber = :rollNumber" (2)
entity-manager="em"> (3)
<int-jpa:parameter name="firstName" expression="payload['firstName']"/> (4)
<int-jpa:parameter name="rollNumber" expression="payload['rollNumber']"/>
</int-jpa:outbound-channel-adapter>| 1 | メッセージが送信チャネルアダプターに送信される入力チャネル。 |
| 2 | 実行する JPA QL。このクエリには、parameter 要素を使用して評価されるパラメーターが含まれる場合があります。 |
| 3 | JPA 操作を実行するためにアダプターが使用するエンティティマネージャー。 |
| 4 | query 属性で指定された JPA QL のパラメーター名の値を定義するために使用される要素(パラメーターごとに 1 つ)。 |
parameter エレメントは、提供された JPA QL で指定された名前付きパラメーターに対応する name を持つ属性を受け入れます(前の例のポイント 2)。パラメーターの値は、静的にすることも、式を使用して導出することもできます。静的値と値を導出する式は、それぞれ value 属性と expression 属性を使用して指定されます。これらの属性は相互に排他的です。
value 属性が指定されている場合、オプションの type 属性を提供できます。この属性の値は、その値が value 属性で表されるクラスの完全修飾名です。デフォルトでは、型は java.lang.String であると想定されています。次の例は、JPA パラメーターを定義する方法を示しています。
<int-jpa:outbound-channel-adapter ...
>
<int-jpa:parameter name="level" value="2" type="java.lang.Integer"/>
<int-jpa:parameter name="name" expression="payload['name']"/>
</int-jpa:outbound-channel-adapter> 前の例が示すように、送信チャネルアダプター要素内で複数の parameter 要素を使用し、静的な値を持つ式などを使用して一部のパラメーターを定義できます。ただし、同じパラメーター名を複数回指定しないように注意してください。JPA クエリで指定された名前付きパラメーターごとに 1 つの parameter 要素を提供する必要があります。例: level と name の 2 つのパラメーターを指定します。level 属性は、型 java.lang.Integer の静的な値ですが、name 属性はメッセージのペイロードから派生しています。
select の指定は JPA QL に対して有効ですが、そうすることは意味がありません。送信チャネルアダプターは結果を返しません。一部の値を選択する場合は、代わりに送信ゲートウェイの使用を検討してください。 |
ネイティブクエリの使用
このセクションでは、ネイティブクエリを使用して JPA 発信チャネルアダプターで操作を実行する方法について説明します。ネイティブクエリの使用は、クエリがネイティブデータベースクエリであることを除いて、JPA QL の使用に似ています。ネイティブクエリを使用すると、データベースベンダーの独立性が失われ、JPA QL を使用することになります。
ネイティブクエリを使用して達成できることの 1 つは、データベースの挿入を実行することです。これは、JPA QL では不可能です。(挿入を実行するには、前述のように、JPA エンティティをチャネルアダプターに送信します)。以下は、ネイティブクエリを使用してテーブルに値を挿入する方法を示す小さな xml フラグメントです。
| 名前付きパラメーターは、ネイティブ SQL クエリと組み合わせて JPA プロバイダーによってサポートされない場合があります。Hibernate では正常に機能しますが、OpenJPA および EclipseLink はそれらをサポートしません。https://issues.apache.org/jira/browse/OPENJPA-111 (英語) を参照してください。JPA 2.0 仕様のセクション 3.8.12 には、「ネイティブクエリには、位置パラメーターのバインドと結果アイテムへの位置アクセスのみを移植可能に使用できる」と記載されています。 |
次の例では、ネイティブクエリで outbound-channel-adapter を構成します。
<int-jpa:outbound-channel-adapter channel="nativeQlChannel"
native-query="insert into STUDENT_TABLE(FIRST_NAME,LAST_UPDATED) values (:lastName,:lastUpdated)" (1)
entity-manager="em">
<int-jpa:parameter name="lastName" expression="payload['updatedLastName']"/>
<int-jpa:parameter name="lastUpdated" expression="new java.util.Date()"/>
</int-jpa:outbound-channel-adapter>| 1 | この送信チャネルアダプターによって実行されるネイティブクエリ。 |
他の属性(channel や entity-manager など)および parameter 要素は、JPA QL の場合と同じセマンティクスを持っていることに注意してください。
名前付きクエリの使用
名前付きクエリの使用は、JPA QL またはネイティブクエリの使用に似ていますが、クエリではなく名前付きクエリを指定する点が異なります。まず、JPA という名前のクエリを定義する方法について説明します。次に、名前付きクエリで機能する送信チャネルアダプターを宣言する方法について説明します。Student というエンティティがある場合、Student クラスのアノテーションを使用して、2 つの名前付きクエリ selectStudent と updateStudent を定義できます。次の例は、その方法を示しています。
@Entity
@Table(name="Student")
@NamedQueries({
@NamedQuery(name="selectStudent",
query="select s from Student s where s.lastName = 'Last One'"),
@NamedQuery(name="updateStudent",
query="update Student s set s.lastName = :lastName,
lastUpdated = :lastUpdated where s.id in (select max(a.id) from Student a)")
})
public class Student {
...
}または、次の例に示すように、orm.xml を使用して名前付きクエリを定義できます。
<entity-mappings ...>
...
<named-query name="selectStudent">
<query>select s from Student s where s.lastName = 'Last One'</query>
</named-query>
</entity-mappings> アノテーションまたは orm.xml を使用して名前付きクエリを定義する方法を示したため、次の例に示すように、名前付きクエリを使用して outbound-channel-adapter を定義する小さな XML フラグメントを示します。
<int-jpa:outbound-channel-adapter channel="namedQueryChannel"
named-query="updateStudent" (1)
entity-manager="em">
<int-jpa:parameter name="lastName" expression="payload['updatedLastName']"/>
<int-jpa:parameter name="lastUpdated" expression="new java.util.Date()"/>
</int-jpa:outbound-channel-adapter>| 1 | チャネル経由でメッセージを受信したときにアダプターに実行させる名前付きクエリ。 |
構成パラメーターのリファレンス
次のリストは、送信チャネルアダプターに設定できるすべての属性を示しています。
<int-jpa:outbound-channel-adapter
auto-startup="true" (1)
channel="" (2)
entity-class="" (3)
entity-manager="" (4)
entity-manager-factory="" (5)
id=""
jpa-operations="" (6)
jpa-query="" (7)
named-query="" (8)
native-query="" (9)
order="" (10)
parameter-source-factory="" (11)
persist-mode="MERGE" (12)
flush="true" (13)
flush-size="10" (14)
clear-on-flush="true" (15)
use-payload-as-parameter-source="true" (16)
<int:poller/>
<int-jpa:transactional/> (17)
<int-jpa:parameter/> (18)
</int-jpa:outbound-channel-adapter>| 1 | このコンポーネントがアプリケーションコンテキストの起動中に起動する必要があるかどうかを示すライフサイクル属性。デフォルトは true です。オプション。 |
| 2 | 送信アダプターが目的の操作を実行するためのメッセージを受信するチャネル。 |
| 3 | JPA オペレーションのエンティティクラスの完全修飾名。entity-class、query、named-query 属性は相互に排他的です。オプション。 |
| 4 | JPA 操作の実行に使用される javax.persistence.EntityManager のインスタンス。オプション。 |
| 5 | JPA 操作を実行する javax.persistence.EntityManager のインスタンスを取得するために使用される javax.persistence.EntityManagerFactory のインスタンス。オプション。 |
| 6 | JPA 操作の実行に使用される org.springframework.integration.jpa.core.JpaOperations の実装。独自の実装を提供するのではなく、デフォルトの org.springframework.integration.jpa.core.DefaultJpaOperations 実装を使用することをお勧めします。entity-manager、entity-manager-factory、jpa-operations 属性のいずれかを使用できます。オプション。 |
| 7 | このアダプターによって実行される JPA QL。オプション。 |
| 8 | このアダプターで実行する必要がある名前付きクエリ。オプション。 |
| 9 | このアダプターによって実行されるネイティブクエリ。jpa-query、named-query、native-query 属性のいずれかを使用できます。オプション。 |
| 10 | 複数のコンシューマーが登録されている場合のこのコンシューマーの順序。これにより、負荷分散とフェイルオーバーが管理されます。デフォルトは Ordered.LOWEST_PRECEDENCE です。オプション。 |
| 11 | o.s.i.jpa.support.parametersource.ParameterSource のインスタンスを取得するために使用される o.s.i.jpa.support.parametersource.ParameterSourceFactory のインスタンス。これは、クエリ内のパラメーターの値を解決するために使用されます。JPA エンティティを使用して操作を実行する場合は無視されます。parameter サブ要素は parameter-source-factory 属性と相互に排他的であり、提供された ParameterSourceFactory で構成する必要があります。オプション。 |
| 12 | 次のいずれかを受け入れます: PERSIST、MERGE、DELETE。アダプターが実行する必要のある操作を示します。JPA 操作にエンティティを使用する場合にのみ関連します。JPA QL、名前付きクエリ、ネイティブクエリを提供する場合は無視されます。デフォルトは MERGE です。オプション。Spring Integration 3.0 の時点で、永続化またはマージするペイロードも java.lang.Iterable (標準 Javadoc) (英語) 型にすることができます。その場合、Iterable によって返される各オブジェクトはエンティティとして扱われ、基になる EntityManager を使用して永続化またはマージされます。イテレータによって返される NULL 値は無視されます。 |
| 13 | 永続化、マージ、削除操作の直後に永続化コンテキストをフラッシュし、EntityManager の flushMode に依存したくない場合は、この値を true に設定します。デフォルトは false です。flush-size 属性を指定しなかった場合にのみ適用されます。この属性が true に設定されている場合、他の値が構成されていなければ、flush-size は暗黙的に 1 に設定されます。 |
| 14 | 永続化、マージまたは削除操作の直後に永続化コンテキストをフラッシュし、EntityManager の flushMode に依存したくない場合は、この属性を "0" より大きい値に設定します。デフォルト値は 0 に設定されており、これは「「フラッシュなし」」を意味します。この属性は、Iterable ペイロードを持つメッセージを対象としています。たとえば、flush-size が 3 に設定されている場合、entityManager.flush() は 3 エンティティごとに呼び出されます。さらに、entityManager.flush() はループ全体の後にもう一度呼び出されます。'flush-size' 属性が "0" より大きい値で指定されている場合、flush 属性を構成する必要はありません。 |
| 15 | 各フラッシュ操作の直後に永続コンテキストをクリアする場合は、この値を "true" に設定します。属性の値が適用されるのは、flush 属性が true に設定されている場合、または flush-size 属性が 0 より大きい値に設定されている場合のみです。 |
| 16 | true に設定すると、メッセージのペイロードがパラメーターのソースとして使用されます。ただし、false に設定されている場合、Message 全体がパラメーターのソースとして使用可能です。オプション。 |
| 17 | JPA アダプターが使用するトランザクション管理属性とトランザクションマネージャーへの参照を定義します。オプション。 |
| 18 | 1 つ以上の parameter 属性 — クエリで使用される各パラメーターに 1 つ。値または式が評価され、パラメーターの値が計算されます。オプション。 |
Java 構成を使用した構成
次の Spring Boot アプリケーションは、Java で送信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
@IntegrationComponentScan
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@MessagingGateway
interface JpaGateway {
@Gateway(requestChannel = "jpaPersistChannel")
@Transactional
void persistStudent(StudentDomain payload);
}
@Bean
public JpaExecutor jpaExecutor() {
JpaExecutor executor = new JpaExecutor(this.entityManagerFactory);
jpaExecutor.setEntityClass(StudentDomain.class);
jpaExecutor.setPersistMode(PersistMode.PERSIST);
return executor;
}
@Bean
@ServiceActivator(channel = "jpaPersistChannel")
public MessageHandler jpaOutbound() {
JpaOutboundGateway adapter = new JpaOutboundGateway(jpaExecutor());
adapter.setProducesReply(false);
return adapter;
}
}Java DSL を使用した構成
次の Spring Boot アプリケーションは、Java DSL で送信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public IntegrationFlow outboundAdapterFlow() {
return f -> f
.handle(Jpa.outboundAdapter(this.entityManagerFactory)
.entityClass(StudentDomain.class)
.persistMode(PersistMode.PERSIST),
e -> e.transactional());
}
}送信ゲートウェイ
JPA 受信チャネルアダプターを使用すると、データベースをポーリングして 1 つ以上の JPA エンティティを取得できます。その結果、取得したデータを使用して、取得したデータをメッセージペイロードとして使用する Spring Integration フローを開始します。
さらに、フローの最後で JPA 送信チャネルアダプターを使用してデータを永続化し、基本的に永続化操作の最後でフローを終了できます。
ただし、フローの途中で JPA 永続化操作を実行するにはどうすればよいですか? 例: Spring Integration メッセージフローで処理しているビジネスデータがあり、それを保持したいが、さらに下流で他のコンポーネントを使用する必要がある場合があります。または、ポーラーを使用してデータベースをポーリングする代わりに、JPQL クエリを実行し、データをアクティブに取得する必要があります。その後、データはフロー内の後続のコンポーネントで処理されます。
これが、JPA 送信ゲートウェイの出番です。データを取得するだけでなく、データを永続化する機能を提供します。これらの使用を容易にするために、Spring Integration は 2 種類の JPA 送信ゲートウェイを提供します。
送信ゲートウェイの更新
送信ゲートウェイの取得
送信ゲートウェイを使用して、データベース内の一部のレコードを保存、更新、削除するアクションを実行する場合は常に、更新する送信ゲートウェイを使用する必要があります。たとえば、entity を使用して永続化する場合、結果としてマージおよび永続化されたエンティティが返されます。その他の場合、影響を受ける(更新または削除された)レコードの数が代わりに返されます。
データベースからデータを取得(選択)するときは、取得送信ゲートウェイを使用します。送信ゲートウェイを取得すると、JPQL、名前付きクエリ(ネイティブまたは JPQL ベース)、またはネイティブクエリ(SQL)を使用してデータを選択し、結果を取得できます。
更新送信ゲートウェイは、JPA 操作の実行後に結果をゲートウェイの応答チャネルに送信することを除いて、関数には送信チャネルアダプターに似ています。
送信ゲートウェイの取得は、受信チャネルアダプターに似ています。
| 一般的な概念のほとんどはそこで説明されているため、最初にこの章で前述した送信チャネルアダプターセクションと受信チャネルアダプターセクションを読むことをお勧めします。 |
この類似性は、共通の機能を可能な限り統合するために主要な JpaExecutor クラスを使用する主な要因でした。
すべての JPA 送信ゲートウェイに共通であり、outbound-channel-adapter と同様、さまざまな JPA 操作の実行に使用できます。
エンティティクラス
JPA クエリ言語 (JPQL)
ネイティブクエリ
名前付きクエリ
構成例については、JPA 送信ゲートウェイのサンプルを参照してください。
共通の構成パラメーター
JPA 送信ゲートウェイは、常に Spring Integration Message に入力としてアクセスできます。その結果、次のパラメーターが使用可能になります。
parameter-source-factoryo.s.i.jpa.support.parametersource.ParameterSourceのインスタンスを取得するために使用されるo.s.i.jpa.support.parametersource.ParameterSourceFactoryのインスタンス。ParameterSourceは、クエリで提供されるパラメーターの値を解決するために使用されます。JPA エンティティを使用して操作を実行する場合、parameter-source-factory属性は無視されます。parameterサブエレメントはparameter-source-factoryと相互に排他的であり、提供されたParameterSourceFactoryで構成する必要があります。オプション。use-payload-as-parameter-sourcetrueに設定すると、Messageのペイロードがパラメーターのソースとして使用されます。falseに設定されている場合、Message全体がパラメーターのソースとして使用可能です。JPA パラメーターが渡されない場合、このプロパティはデフォルトでtrueになります。つまり、デフォルトのBeanPropertyParameterSourceFactoryを使用すると、ペイロードの Bean プロパティが JPA クエリのパラメーター値のソースとして使用されます。ただし、JPA パラメーターが渡された場合、このプロパティはデフォルトでfalseに評価されます。その理由は、JPA パラメーターを使用すると SpEL 式を提供できるからです。ヘッダーを含むMessage全体にアクセスできることは非常に有益です。オプション。
送信ゲートウェイの更新
次のリストは、updateing-outbound-gateway に設定できるすべての属性を示し、主要な属性について説明しています。
<int-jpa:updating-outbound-gateway request-channel="" (1)
auto-startup="true"
entity-class=""
entity-manager=""
entity-manager-factory=""
id=""
jpa-operations=""
jpa-query=""
named-query=""
native-query=""
order=""
parameter-source-factory=""
persist-mode="MERGE"
reply-channel="" (2)
reply-timeout="" (3)
use-payload-as-parameter-source="true">
<int:poller/>
<int-jpa:transactional/>
<int-jpa:parameter name="" type="" value=""/>
<int-jpa:parameter name="" expression=""/>
</int-jpa:updating-outbound-gateway>| 1 | 送信ゲートウェイが目的の操作を実行するためのメッセージを受信するチャネル。この属性は、outbound-channel-adapter の channel 属性に似ています。オプション。 |
| 2 | ゲートウェイが必要な JPA 操作を実行した後にレスポンスを送信するチャネル。この属性が定義されていない場合、リクエストメッセージには replyChannel ヘッダーが必要です。オプション。 |
| 3 | ゲートウェイが結果を応答チャネルに送信するのを待つ時間を指定します。応答チャネル自体が送信操作をブロックする可能性がある場合にのみ適用されます(たとえば、現在いっぱいのバウンド QueueChannel)。デフォルトでは、ゲートウェイは無期限に待機します。値はミリ秒単位で指定されます。オプション。 |
残りの属性については、この章で前述しています。構成パラメーターのリファレンスおよび構成パラメーターのリファレンスを参照してください。
Java 構成を使用した構成
次の Spring Boot アプリケーションは、Java で送信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
@IntegrationComponentScan
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@MessagingGateway
interface JpaGateway {
@Gateway(requestChannel = "jpaUpdateChannel")
@Transactional
void updateStudent(StudentDomain payload);
}
@Bean
@ServiceActivator(channel = "jpaUpdateChannel")
public MessageHandler jpaOutbound() {
JpaOutboundGateway adapter =
new JpaOutboundGateway(new JpaExecutor(this.entityManagerFactory));
adapter.setOutputChannelName("updateResults");
return adapter;
}
}Java DSL を使用した構成
次の Spring Boot アプリケーションは、Java DSL を使用して送信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public IntegrationFlow updatingGatewayFlow() {
return f -> f
.handle(Jpa.updatingGateway(this.entityManagerFactory),
e -> e.transactional(true))
.channel(c -> c.queue("updateResults"));
}
}送信ゲートウェイの取得
次の例は、取得する送信ゲートウェイに設定できるすべての属性を示し、キー属性を説明しています。
<int-jpa:retrieving-outbound-gateway request-channel=""
auto-startup="true"
delete-after-poll="false"
delete-in-batch="false"
entity-class=""
id-expression="" (1)
entity-manager=""
entity-manager-factory=""
expect-single-result="false" (2)
id=""
jpa-operations=""
jpa-query=""
max-results="" (3)
max-results-expression="" (4)
first-result="" (5)
first-result-expression="" (6)
named-query=""
native-query=""
order=""
parameter-source-factory=""
reply-channel=""
reply-timeout=""
use-payload-as-parameter-source="true">
<int:poller></int:poller>
<int-jpa:transactional/>
<int-jpa:parameter name="" type="" value=""/>
<int-jpa:parameter name="" expression=""/>
</int-jpa:retrieving-outbound-gateway>| 1 | (Spring Integration 4.0 以降)評価コンテキストのルートオブジェクトとしての requestMessage に対する EntityManager.find(Class entityClass, Object primaryKey) メソッドの primaryKey 値を決定する SpEL 式。entityClass 引数は、存在する場合、entity-class 属性から決定されます。それ以外の場合は、payload クラスから決定されます。id-expression を使用する場合、他のすべての属性は許可されません。オプション。 |
| 2 | 選択操作が単一の結果を返すか、結果の List を返すかを示すブールフラグ。このフラグが true に設定されている場合、単一のエンティティがメッセージのペイロードとして送信されます。複数のエンティティが返されると、例外がスローされます。false の場合、エンティティの List がメッセージのペイロードとして送信されます。デフォルトは false です。オプション。 |
| 3 | この非ゼロ、非負の整数値は、選択操作の実行時に、指定された行数を超える行を選択しないようアダプターに指示します。デフォルトでは、この属性が設定されていない場合、指定されたクエリによってすべての可能なレコードが選択されます。この属性は max-results-expression と相互に排他的です。オプション。 |
| 4 | 結果セット内の結果の最大数を見つけるために使用できる式。max-results と相互に排他的です。オプション。 |
| 5 | この非ゼロ、非負の整数値は、結果を取得する最初のレコードをアダプターに伝えます。この属性は first-result-expression と相互に排他的です。バージョン 3.0 はこの属性を導入しました。オプション。 |
| 6 | この式はメッセージに対して評価され、結果セットの最初のレコードの位置を見つけます。この属性は、first-result と相互に排他的です。バージョン 3.0 はこの属性を導入しました。オプション。 |
残りの属性については、この章で前述しています。構成パラメーターのリファレンスおよび構成パラメーターのリファレンスを参照してください。
Java 構成を使用した構成
次の Spring Boot アプリケーションは、Java で送信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public JpaExecutor jpaExecutor() {
JpaExecutor executor = new JpaExecutor(this.entityManagerFactory);
jpaExecutor.setJpaQuery("from Student s where s.id = :id");
executor.setJpaParameters(Collections.singletonList(new JpaParameter("id", null, "payload")));
jpaExecutor.setExpectSingleResult(true);
return executor;
}
@Bean
@ServiceActivator(channel = "jpaRetrievingChannel")
public MessageHandler jpaOutbound() {
JpaOutboundGateway adapter = new JpaOutboundGateway(jpaExecutor());
adapter.setOutputChannelName("retrieveResults");
adapter.setGatewayType(OutboundGatewayType.RETRIEVING);
return adapter;
}
}Java DSL を使用した構成
次の Spring Boot アプリケーションは、Java DSL で送信アダプターを構成する方法の例を示しています。
@SpringBootApplication
@EntityScan(basePackageClasses = StudentDomain.class)
public class JpaJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(JpaJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public IntegrationFlow retrievingGatewayFlow() {
return f -> f
.handle(Jpa.retrievingGateway(this.entityManagerFactory)
.jpaQuery("from Student s where s.id = :id")
.expectSingleResult(true)
.parameterExpression("id", "payload"))
.channel(c -> c.queue("retrieveResults"));
}
}取得時にエンティティを削除することを選択し、エンティティのコレクションを取得した場合、デフォルトでは、エンティティはエンティティごとに削除されます。これにより、パフォーマンスの問題が発生する場合があります。 または、属性 JSR 317: Java ™ Persistence 2.0 の章では、4.10 の「一括更新および削除操作」で次のように述べています。 “削除操作は、指定されたクラスとそのサブクラスのエンティティにのみ適用されます。関連するエンティティにはカスケードしません。” 詳細については、JSR 317: Java ™ Persistence 2.0 (英語) を参照してください。 |
JPA 送信ゲートウェイのサンプル
このセクションには、送信ゲートウェイの更新と送信ゲートウェイの取得のさまざまな使用例が含まれています。
エンティティクラスを使用して更新する
次の例では、org.springframework.integration.jpa.test.entity.Student エンティティクラスを JPA 定義パラメーターとして使用することにより、送信ゲートウェイの更新が永続化されます。
<int-jpa:updating-outbound-gateway request-channel="entityRequestChannel" (1)
reply-channel="entityResponseChannel" (2)
entity-class="org.springframework.integration.jpa.test.entity.Student"
entity-manager="em"/>| 1 | これは、送信ゲートウェイのリクエストチャネルです。outbound-channel-adapter の channel 属性に似ています。 |
| 2 | これは、ゲートウェイが送信アダプターと異なる場所です。これは、JPA 操作からの応答が受信されるチャネルです。ただし、受信した応答に関心がなく、操作のみを実行する場合は、JPA outbound-channel-adapter を使用するのが適切な選択です。エンティティクラスを使用するこの例では、応答は JPA 操作の結果として作成またはマージされたエンティティオブジェクトです。 |
JPQL を使用した更新
次の例では、Java Persistence Query Language(JPQL)を使用してエンティティを更新します。これは、更新送信ゲートウェイの使用を義務付けています。
<int-jpa:updating-outbound-gateway request-channel="jpaqlRequestChannel"
reply-channel="jpaqlResponseChannel"
jpa-query="update Student s set s.lastName = :lastName where s.rollNumber = :rollNumber" (1)
entity-manager="em">
<int-jpa:parameter name="lastName" expression="payload"/>
<int-jpa:parameter name="rollNumber" expression="headers['rollNumber']"/>
</int-jpa:updating-outbound-gateway>| 1 | ゲートウェイが実行する JPQL クエリ。送信ゲートウェイの更新を使用したため、update および delete JPQL クエリのみが実用的な選択になります。 |
long 値を持つ rollNumber というヘッダーも含む String ペイロードを持つメッセージを送信すると、指定されたロール番号を持つ生徒の姓がメッセージペイロードの値に更新されます。更新ゲートウェイを使用する場合、戻り値は常に整数値であり、JPA QL の実行によって影響を受けるレコードの数を示します。
JPQL を使用したエンティティの取得
次の例では、送信ゲートウェイと JPQL の取得を使用して、データベースから 1 つ以上のエンティティを取得(選択)します。
<int-jpa:retrieving-outbound-gateway request-channel="retrievingGatewayReqChannel"
reply-channel="retrievingGatewayReplyChannel"
jpa-query="select s from Student s where s.firstName = :firstName and s.lastName = :lastName"
entity-manager="em">
<int-jpa:parameter name="firstName" expression="payload"/>
<int-jpa:parameter name="lastName" expression="headers['lastName']"/>
</int-jpa:outbound-gateway>id-expression を使用してエンティティを取得する
次の例では、id-expression で送信ゲートウェイを取得して、データベースから唯一のエンティティを取得(検索)します。primaryKey は id-expression 評価の結果です。entityClass は、メッセージ payload のクラスです。
<int-jpa:retrieving-outbound-gateway
request-channel="retrievingGatewayReqChannel"
reply-channel="retrievingGatewayReplyChannel"
id-expression="payload.id"
entity-manager="em"/>名前付きクエリを使用して更新する
名前付きクエリを使用することは、基本的に JPQL クエリを直接使用することと同じです。違いは、次の例に示すように、代わりに named-query 属性が使用されることです。
<int-jpa:updating-outbound-gateway request-channel="namedQueryRequestChannel"
reply-channel="namedQueryResponseChannel"
named-query="updateStudentByRollNumber"
entity-manager="em">
<int-jpa:parameter name="lastName" expression="payload"/>
<int-jpa:parameter name="rollNumber" expression="headers['rollNumber']"/>
</int-jpa:outbound-gateway>| Spring Integration の JPA アダプターを使用する完全なサンプルアプリケーションはこちらにあります [GitHub] (英語) 。 |