Spring Integration’s JPA (Java Persistence API) module provides components for performing various database operations using JPA. The following components are provided:
These components can be used to perform select, create, update and delete operations on the target databases by sending/receiving messages to them.
The JPA Inbound Channel Adapter lets you poll and retrieve (select) data from the database using JPA whereas the JPA Outbound Channel Adapter lets you create, update and delete entities.
Outbound Gateways for JPA can be used to persist entities to the database, yet allowing you to continue with the flow and execute further components downstream. Similarly, you can use an Outbound Gateway to retrieve entities from the database.
For example, you may use the Outbound Gateway, which receives a Message with a userId
as payload on its request channel, to query the database and retrieve the User entity and pass it downstream for further processing.
Recognizing these semantic differences, Spring Integration provides 2 separate JPA Outbound Gateways:
Functionality
All JPA components perform their respective JPA operations by using either one of the following:
In the following sections we will describe each of these components in more detail.
The Spring Integration JPA support has been tested using the following persistence providers:
When using a persistence provider, please ensure that the provider is compatible with JPA 2.1.
Each of the provided components uses the o.s.i.jpa.core.JpaExecutor
class which, in turn, uses an implementation of the o.s.i.jpa.core.JpaOperations
interface.
JpaOperations
operates like a typical Data Access Object (DAO) and provides methods such as find, persist, executeUpdate etc.
For most use cases the provided default implementation o.s.i.jpa.core.DefaultJpaOperations
should be sufficient.
Nevertheless, you have the option to specify your own implementation in case you require custom behavior.
For initializing a JpaExecutor
you have to use one of 3 available constructors that accept one of:
@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; }
When using XML namespace support, the underlying parser classes will instantiate the relevant Java classes for you. Thus, you typically don’t have to deal with the inner workings of the JPA adapter. This section will document the XML Namespace Support provided by the Spring Integration and will show you how to use the XML Namespace Support to configure the Jpa components.
Certain configuration parameters are shared amongst all JPA components and are described below:
auto-startup
Lifecycle attribute signaling if this component should be started during Application Context startup.
Defaults to true
.
Optional.
id
Identifies the underlying Spring bean definition, which is an instance of either EventDrivenConsumer
or PollingConsumer
.
Optional.
entity-manager-factory
The reference to the JPA Entity Manager Factory that will be used by the adapter to create the EntityManager
.
Either this attribute or the entity-manager attribute or the jpa-operations attribute must be provided.
entity-manager
The reference to the JPA Entity Manager that will be used by the component. Either this attribute or the entity-manager-factory attribute or the jpa-operations attribute must be provided.
Note | |
---|---|
Usually your Spring Application Context only defines a JPA Entity Manager Factory and the |
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean"> <property name="entityManagerFactory" ref="entityManagerFactoryBean" /> </bean>
jpa-operations
Reference to a bean implementing the JpaOperations
interface.
In rare cases it might be advisable to provide your own implementation of the JpaOperations
interface, instead of relying on the default implementation org.springframework.integration.jpa.core.DefaultJpaOperations
.
As JpaOperations
wraps the necessary datasource; the JPA Entity Manager or JPA Entity Manager Factory must not be provided, if the jpa-operations attribute is used.
entity-class
The fully qualified name of the entity class. The exact semantics of this attribute vary, depending on whether we are performing a persist/update operation or whether we are retrieving objects from the database.
When retrieving data, you can specify the entity-class attribute to indicate that you would like to retrieve objects of this type from the database. In that case you must not define any of the query attributes ( jpa-query, native-query or named-query )
When persisting data, the entity-class attribute will indicate the type of object to persist. If not specified (for persist operations) the entity class will be automatically retrieved from the Message’s payload.
jpa-query
Defines the JPA query (Java Persistence Query Language) to be used.
native-query
Defines the native SQL query to be used.
named-query
This attribute refers to a named query. A named query can either be defined in Native SQL or JPAQL but the underlying JPA persistence provider handles that distinction internally.
For providing parameters, the parameter XML sub-element can be used. It provides a mechanism to provide parameters for the queries that are either based on the Java Persistence Query Language (JPQL) or native SQL queries. Parameters can also be provided for Named Queries.
Expression based Parameters
<int-jpa:parameter expression="payload.name" name="firstName"/>
Value based Parameters
<int-jpa:parameter name="name" type="java.lang.String" value="myName"/>
Positional Parameters
<int-jpa:parameter expression="payload.name"/> <int-jpa:parameter type="java.lang.Integer" value="21"/>
All JPA operations like INSERT
, UPDATE
and DELETE
require a transaction to be active whenever they are performed.
For Inbound Channel Adapters there is nothing special to be done, it is similar to the way we configure transaction managers with pollers used with other inbound channel adapters.
The xml snippet below shows a sample where a transaction manager is configured with the poller used with an Inbound Channel Adapter.
<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>
However, it may be necessary to specifically start a transaction when using an Outbound Channel Adapter/Gateway. If a DirectChannel is an input channel for the outbound adapter/gateway, and if transaction is active in the current thread of execution, the JPA operation will be performed in the same transaction context. We can also configure to execute this JPA operation in a new transaction as below.
<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>
As we can see above, the transactional sub element of the outbound gateway/adapter will be used to specify the transaction attributes. It is optional to define this child element if you have DirectChannel as an input channel to the adapter and you want the adapter to execute the operations in the same transaction context as the caller. If, however, you are using an ExecutorChannel, it is required to have the transactional sub element as the invoking client’s transaction context is not propagated.
Note | |
---|---|
Unlike the transactional sub element of the poller which is defined in the spring integration’s namespace, the transactional sub element for the outbound gateway/adapter is defined in the jpa namespace. |
An Inbound Channel Adapter is used to execute a select query over the database using JPA QL and return the result.
The message payload will be either a single entity or a List
of entities.
Below is a sample xml snippet that shows a sample usage of inbound-channel-adapter.
<int-jpa:inbound-channel-adapter channel="inboundChannelAdapterOne" entity-manager="em" auto-startup="true" query="select s from Student s" expect-single-result="true" max-results="" max-results-expression="" delete-after-poll="true" flush-after-delete="true"> <int:poller fixed-rate="2000" > <int:transactional propagation="REQUIRED" transaction-manager="transactionManager"/> </int:poller> </int-jpa:inbound-channel-adapter>
The channel over which the inbound-channel-adapter will put the messages with the payload received after executing the provided JPA QL in the query attribute. | |
The | |
Attribute signalling if the component should be automatically started on startup of the Application Context.
The value defaults to | |
The JPA QL that needs to be executed and whose result needs to be sent out as the payload of the message | |
The attribute that tells if the executed JPQL query gives a single entity in the result or a | |
This non zero, non negative integer value tells the adapter not to select more than given number of rows on execution of the select operation.
By default, if this attribute is not set, all the possible records are selected by given query.
This attribute is mutually exclusive with | |
An expression, mutually exclusive with | |
Set this value to | |
Set this value to |
<int-jpa:inbound-channel-adapter auto-startup="true" channel="" delete-after-poll="false" delete-per-row="false" entity-class="" entity-manager="" entity-manager-factory="" expect-single-result="false" id="" jpa-operations="" jpa-query="" named-query="" native-query="" parameter-source="" send-timeout=""> <int:poller ref="myPoller"/> </int-jpa:inbound-channel-adapter>
This Lifecycle attribute signaled if this component should be started during startup of the Application Context. This attribute defaults to true.Optional. | |
The channel to which the adapter will send a message with the payload that was received after performing the desired JPA operation. | |
A boolean flag that indicates whether the records selected are to be deleted after they are being polled by the adapter.
By default the value is | |
A boolean flag that indicates whether the records can be deleted in bulk or are deleted one record at a time.
By default the value is | |
The fully qualified name of the entity class that would be queried from the database. The adapter will automatically build a JPA Query to be executed based on the entity class name provided.Optional. | |
An instance of | |
An instance of | |
A boolean flag indicating whether the select operation is expected to return a single result or a | |
An implementation of | |
The JPA QL that needs to be executed by this adapter.Optional. | |
The named query that needs to be executed by this adapter.Optional. | |
The native query that will be executed by this adapter. Either of the jpa-query, named-query,entity-class or native-query attributes are to be used. Optional. | |
An implementation of | |
Maximum amount of time in milliseconds to wait when sending a message to the channel.Optional. |
The following Spring Boot application provides an example of configuring the inbound adapter using Java configuration:
@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()); } }
The following Spring Boot application provides an example of configuring the Inbound Adapter using the 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(); } }
The JPA Outbound channel adapter allows you to accept messages over a request channel. The payload can either be used as the entity to be persisted, or used along with the headers in parameter expressions for a defined JPQL query to be executed. In the following sub sections we shall see what those possible ways of performing these operations are.
The XML snippet below shows how we can use the Outbound Channel Adapter to persist an entity to the database.
<int-jpa:outbound-channel-adapter channel="entityTypeChannel" entity-class="org.springframework.integration.jpa.test.entity.Student" persist-mode="PERSIST" entity-manager="em"/ >
The channel over which a valid JPA entity will be sent to the JPA Outbound Channel Adapter. | |
The fully qualified name of the entity class that would be accepted by the adapter to be persisted in the database. You can actually leave off this attribute in most cases as the adapter can determine the entity class automatically from the Spring Integration Message payload. | |
The operation that needs to be done by the adapter, valid values are PERSIST, MERGE and DELETE. The default value is MERGE. | |
The JPA entity manager to be used. |
As we can see above these 4 attributes of the outbound-channel-adapter are all we need to configure it to accept entities over the input channel and process them to PERSIST,MERGE or DELETE it from the underlying data source.
Note | |
---|---|
As of Spring Integration 3.0, payloads to PERSIST or MERGE can also be of type |
We have seen in the above sub section how to perform a PERSIST action using an entity We will now see how to use the outbound channel adapter which uses JPA QL (Java Persistence API Query Language)
<int-jpa:outbound-channel-adapter channel="jpaQlChannel" jpa-query="update Student s set s.firstName = :firstName where s.rollNumber = :rollNumber" entity-manager="em"> <int-jpa:parameter name="firstName" expression="payload['firstName']"/> <int-jpa:parameter name="rollNumber" expression="payload['rollNumber']"/> </int-jpa:outbound-channel-adapter>
The input channel over which the message is being sent to the outbound channel adapter | |
The JPA QL that needs to be executed.This query may contain parameters that will be evaluated using the parameter child tag. | |
The entity manager used by the adapter to perform the JPA operations | |
This sub element, one for each parameter will be used to evaluate the value of the parameter names specified in the JPA QL specified in the query attribute |
The parameter sub element accepts an attribute name which corresponds to the named parameter specified in the provided JPA QL (point 2 in the above mentioned sample). The value of the parameter can either be static or can be derived using an expression. The static value and the expression to derive the value is specified using the value and the expression attributes respectively. These attributes are mutually exclusive.
If the value attribute is specified we can provide an optional type attribute.
The value of this attribute is the fully qualified name of the class whose value is represented by the value attribute.
By default the type is assumed to be a java.lang.String
.
<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>
As seen in the above snippet, it is perfectly valid to use multiple parameter sub elements within an outbound channel adapter tag and derive some parameters using expressions and some with static value.
However, care should be taken not to specify the same parameter name multiple times, and, provide one parameter sub element for each named parameter specified in the JPA query.
For example, we are specifying two parameters level and name where level attribute is a static value of type java.lang.Integer
, where as the name attribute is derived from the payload of the message
Note | |
---|---|
Though specifying select is valid for JPA QL, it makes no sense as outbound channel adapters will not be returning any result. If you want to select some values, consider using the outbound gateway instead. |
In this section we will see how to use native queries to perform the operations using JPA outbound channel adapter. Using native queries is similar to using JPA QL, except that the query specified here is a native database query. By choosing native queries we lose the database vendor independence which we get using JPA QL.
One of the things we can achieve using native queries is to perform database inserts, which is not possible using JPA QL (To perform inserts we send JPA entities to the channel adapter as we have seen earlier). Below is a small xml fragment that demonstrates the use of native query to insert values in a table. Please note that we have only mentioned the important attributes below. All other attributes like channel, entity-manager and the parameter sub element has the same semantics as when we use JPA QL.
Important | |
---|---|
Please be aware that named parameters may not be supported by your JPA provider in conjunction with native SQL queries. While they work fine using Hibernate, OpenJPA and EclipseLink do NOT support them: https://issues.apache.org/jira/browse/OPENJPA-111 Section 3.8.12 of the JPA 2.0 spec states: "Only positional parameter binding and positional access to result items may be portably used for native queries." |
<int-jpa:outbound-channel-adapter channel="nativeQlChannel" native-query="insert into STUDENT_TABLE(FIRST_NAME,LAST_UPDATED) values (:lastName,:lastUpdated)" 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>
We will now see how to use named queries after seeing using entity, JPA QL and native query in previous sub sections. Using named query is also very similar to using JPA QL or a native query, except that we specify a named query instead of a query. Before we go further and see the xml fragment for the declaration of the outbound-channel-adapter, we will see how named JPA named queries are defined.
In our case, if we have an entity called Student
, then we have the following in the class to define two named queries selectStudent and updateStudent.
Below is a way to define named queries using annotations
@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 { ...
You can alternatively use the orm.xml to define named queries as seen below
<entity-mappings ...> ... <named-query name="selectStudent"> <query>select s from Student s where s.lastName = 'Last One'</query> </named-query> </entity-mappings>
Now that we have seen how we can define named queries using annotations or using orm.xml, we will now see a small xml fragment for defining an outbound-channel-adapter using named query
<int-jpa:outbound-channel-adapter channel="namedQueryChannel" named-query="updateStudent" 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>
<int-jpa:outbound-channel-adapter auto-startup="true" channel="" entity-class="" entity-manager="" entity-manager-factory="" id="" jpa-operations="" jpa-query="" named-query="" native-query="" order="" parameter-source-factory="" persist-mode="MERGE" flush="true" flush-size="10" clear-on-flush="true" use-payload-as-parameter-source="true" (16) <int:poller/> <int-jpa:transactional/> (17) <int-jpa:parameter/> (18) </int-jpa:outbound-channel-adapter>
Lifecycle attribute signaling if this component should be started during Application Context startup.
Defaults to | |
The channel from which the outbound adapter will receive messages for performing the desired operation. | |
The fully qualified name of the entity class for the JPA Operation. The attributes entity-class, query and named-query are mutually exclusive. Optional. | |
An instance of | |
An instance of | |
An implementation of | |
The JPA QL that needs to be executed by this adapter.Optional. | |
The named query that needs to be executed by this adapter.Optional. | |
The native query that will be executed by this adapter. Either of the jpa-query, named-query or native-query attributes are to be used. Optional. | |
The order for this consumer when multiple consumers are registered thereby managing load- balancing and/or failover. Optional (Defaults to Ordered.LOWEST_PRECEDENCE). | |
An instance of | |
Accepts one of the following: PERSIST, MERGE or DELETE.
Indicates the operation that the adapter needs to perform.
Relevant only if an entity is being used for JPA operations.
Ignored if JPA QL, named query or native query is provided.
Defaults to MERGE.
Optional.
As of Spring Integration 3.0, payloads to persist or merge can also be of type | |
Set this value to | |
Set this attribute to a value greater than 0 if you want to flush the persistence context immediately after persist, merge or delete operations and don’t want to rely on the | |
Set this value to true if you want to clear persistence context immediately after each flush operation.
The attribute’s value is applied only if the | |
If set to true, the payload of the Message will be used as a source for providing parameters. If false, however, the entire Message will be available as a source for parameters.Optional. | |
Defines the transaction management attributes and the reference to transaction manager to be used by the JPA adapter.Optional. | |
One or more parameter attributes, one for each parameter used in the query. The value or expression provided will be evaluated to compute the value of the parameter.Optional. |
The following Spring Boot application provides an example of configuring the inbound adapter using Java configuration:
@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; } }
The following Spring Boot application provides an example of configuring the Inbound Adapter using the 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()); } }
The JPA Inbound Channel Adapter allows you to poll a database in order to retrieve one or more JPA entities and the retrieved data is consequently used to start a Spring Integration flow using the retrieved data as message payload.
Additionally, you may use JPA Outbound Channel Adapters at the end of your flow in order to persist data, essentially terminating the flow at the end of the persistence operation.
However, how can you execute JPA persistence operation in the middle of a flow? For example, you may have business data that you are processing in your Spring Integration message flow, that you would like to persist, yet you still need to execute other components further downstream. Or instead of polling the database using a poller, you rather have the need to execute JPQL queries and retrieve data actively which then is used to being processed in subsequent components within your flow.
This is where JPA Outbound Gateways come into play. They give you the ability to persist data as well as retrieving data. To facilitate these uses, Spring Integration provides two types of JPA Outbound Gateways:
Whenever the Outbound Gateway is used to perform an action that saves, updates or solely deletes some records in the database, you need to use an Updating Outbound Gateway gateway. If for example an entity is used to persist it, then a merged/persisted entity is returned as a result. In other cases the number of records affected (updated or deleted) is returned instead.
When retrieving (selecting) data from the database, we use a Retrieving Outbound Gateway. With a Retrieving Outbound Gateway gateway, we can use either JPQL, Named Queries (native or JPQL-based) or Native Queries (SQL) for selecting the data and retrieving the results.
An Updating Outbound Gateway is functionally very similar to an Outbound Channel Adapter, except that an Updating Outbound Gateway is used to send a result to the Gateway’s reply channel after performing the given JPA operation.
A Retrieving Outbound Gateway is quite similar to an Inbound Channel Adapter.
Note | |
---|---|
We recommend you to first refer to the JPA Outbound Channel Adapter section and the JPA Inbound Channel Adapter sections above, as most of the common concepts are being explained there. |
This similarity was the main factor to use the central JpaExecutor
class to unify common functionality as much as possible.
Common for all JPA Outbound Gateways and simlar to the outbound-channel-adapter, we can use
for performing various JPA operations. For configuration examples please see Section 20.6.8, “JPA Outbound Gateway Samples”.
JPA Outbound Gateways always have access to the Spring Integration Message as input. As such the following parameters are available:
parameter-source-factory
An instance of o.s.i.jpa.support.parametersource.ParameterSourceFactory
that will be used to get an instance of o.s.i.jpa.support.parametersource.ParameterSource
.
The ParameterSource is used to resolve the values of the parameters provided in the query.
The_parameter-source-factory_ attribute is ignored, if operations are performed using a JPA entity.
If a parameter sub-element is used, the factory must be of type ExpressionEvaluatingParameterSourceFactory
, located in package o.s.i.jpa.support.parametersource.
Optional.
use-payload-as-parameter-source
If set to true, the payload of the Message will be used as a source for providing parameters.
If set to false, the entire Message will be available as a source for parameters.
If no JPA Parameters are passed in, this property will default to true.
This means that using a default BeanPropertyParameterSourceFactory
, the bean properties of the payload will be used as a source for parameter values for the to-be-executed JPA query.
However, if JPA Parameters are passed in, then this property will by default evaluate to false.
The reason is that JPA Parameters allow for SpEL Expressions to be provided and therefore it is highly beneficial to have access to the entire Message, including the Headers.
<int-jpa:updating-outbound-gateway request-channel="" 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="" reply-timeout="" 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>
The channel from which the outbound gateway will receive messages for performing the desired operation. This attribute is similar to channel attribute of the outbound-channel-adapter.Optional. | |
The channel to which the gateway will send the response after performing the required JPA operation. If this attribute is not defined, the request message must have a replyChannel header. Optional. | |
Specifies the time the gateway will wait to send the result to the reply channel. Only applies when the reply channel itself might block the send (for example a bounded QueueChannel that is currently full). By default the Gateway will wait indefinitely. The value is specified in milliseconds. Optional. |
The following Spring Boot application provides an example of configuring the inbound adapter using Java configuration:
@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; } }
The following Spring Boot application provides an example of configuring the Inbound Adapter using the 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="" entity-manager="" entity-manager-factory="" expect-single-result="false" id="" jpa-operations="" jpa-query="" max-results="" max-results-expression="" first-result="" first-result-expression="" 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>
(Since Spring Integration 4.0) The SpEL expression to determine the | |
A boolean flag indicating whether the select operation is expected to return a single result or a | |
This non zero, non negative integer value tells the adapter not to select more than given number of rows on execution of the select operation.
By default, if this attribute is not set, all the possible records are selected by given query.
This attribute is mutually exclusive with | |
An expression, mutually exclusive with | |
This non zero, non negative integer value tells the adapter the first record from which the results are to be retrieved This attribute is mutually exclusive to | |
This expression is evaluated against the message to find the position of first record in the result set to be retrieved This attribute is mutually exclusive to |
The following Spring Boot application provides an example of configuring the inbound adapter using Java configuration:
@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; } }
The following Spring Boot application provides an example of configuring the Inbound Adapter using the 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")); } }
Important | |
---|---|
When choosing to delete entities upon retrieval and you have retrieved a collection of entities, please be aware that by default entities are deleted on a per entity basis. This may cause performance issues. Alternatively, you can set attribute deleteInBatch to true, which will perform a batch delete. However, please be aware of the limitation that in that case cascading deletes are not supported. JSR 317: Java™ Persistence 2.0 states in chapter Chapter 4.10, Bulk Update and Delete Operations that: "A delete operation only applies to entities of the specified class and its subclasses. It does not cascade to related entities." For more information please see JSR 317: Java™ Persistence 2.0 |
This section contains various examples of the Updating Outbound Gateway and Retrieving Outbound Gateway
Update using an Entity Class
In this example an Updating Outbound Gateway is persisted using solely the entity class org.springframework.integration.jpa.test.entity.Student
as JPA defining parameter.
<int-jpa:updating-outbound-gateway request-channel="entityRequestChannel" reply-channel="entityResponseChannel" entity-class="org.springframework.integration.jpa.test.entity.Student" entity-manager="em"/>
This is the request channel for the outbound gateway, this is similar to the channel attribute of the outbound-channel-adapter | |
This is where a gateway differs from an outbound adapter, this is the channel over which the reply of the performed JPA operation is received. If,however, you are not interested in the reply received and just want to perform the operation, then using a JPA outbound-channel-adapter is the appropriate choice. In above case, where we are using entity class, the reply will be the entity object that was created/merged as a result of the JPA operation. |
Update using JPQL
In this example, we will see how we can update an entity using the Java Persistence Query Language (JPQL). For this we use an_Updating Outbound Gateway_.
<int-jpa:updating-outbound-gateway request-channel="jpaqlRequestChannel" reply-channel="jpaqlResponseChannel" jpa-query="update Student s set s.lastName = :lastName where s.rollNumber = :rollNumber" entity-manager="em"> <int-jpa:parameter name="lastName" expression="payload"/> <int-jpa:parameter name="rollNumber" expression="headers['rollNumber']"/> </int-jpa:updating-outbound-gateway>
The JPQL query that will be executed by the gateway. Since an Updating Outbound Gateway is used, only update and delete JPQL queries would be sensible choices. |
When sending a message with a String payload and containing a header rollNumber with a long value, the last name of the student with the provided roll number is updated to the value provided in the message payload. When using an UPDATING gateway, the return value is always an integer value which denotes the number of records affected by execution of the JPA QL.
Retrieving an Entity using JPQL
The following examples uses a Retrieving Outbound Gateway together with JPQL to retrieve (select) one or more entities from the database.
<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>
Retrieving an Entity using id-expression
The following examples uses a Retrieving Outbound Gateway together with id-expression
to retrieve (find) one and only one entity from the database.
The primaryKey
is the result of id-expression
evaluation.
The entityClass
is a class of Message payload
.
<int-jpa:retrieving-outbound-gateway request-channel="retrievingGatewayReqChannel" reply-channel="retrievingGatewayReplyChannel" id-expression="payload.id" entity-manager="em"/>
Update using a Named Query
Using a Named Query is basically the same as using a JPQL query directly. The difference is that the named-query attribute is used instead, as seen in the xml snippet below.
<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>
Note | |
---|---|
You can find a complete Sample application for using Spring Integration’s JPA adapter at jpa sample. |