Outbound Channel Adapter
JPA 出站通道适配器允许您接受一个请求通道上的消息。有效负载可以被用作要持久化的实体,也可以与参数表达式中的标头一起用于 JPQL 查询。以下几节涵盖了执行这些操作的可能方式。
The JPA outbound channel adapter lets you accept messages over a request channel. The payload can either be used as the entity to be persisted or used with the headers in the parameter expressions for a JPQL query. The following sections cover the possible ways of performing these operations.
Using an Entity Class
以下XML将输出通道适配器配置为将实体持久化到数据库:
The following XML configures the outbound channel adapter to persist an entity to the database:
<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 | The channel over which a valid JPA entity is sent to the JPA outbound channel adapter. |
2 | The fully qualified name of the entity class 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. |
3 | The operation to be done by the adapter.
The valid values are PERSIST , MERGE , and DELETE .
The default value is MERGE . |
4 | The JPA entity manager to be used. |
`outbound-channel-adapter`的这四个属性配置它以通过输入通道接受实体,并将它们处理为从底层数据源中“持久化”、“合并”或“删除”实体。
These four attributes of the outbound-channel-adapter
configure it to accept entities over the input channel and process them to PERSIST
, MERGE
, or DELETE
the entities from the underlying data source.
从 Spring Integration 3.0 开始,到 |
As of Spring Integration 3.0, payloads to |
从版本 5.5.4 开始, |
Starting with version 5.5.4, the |
Using JPA Query Language (JPA QL)
previous section 展示了如何使用实体执行一个 PERSIST
操作。本节演示如何将出站通道适配器和 JPA QL 一起使用。
The previous section showed how to perform a PERSIST
action by using an entity.
This section shows how to use an outbound channel adapter with JPA QL.
以下XML将输出通道适配器配置为将实体持久化到数据库:
The following XML configures the outbound channel adapter to persist an entity to the database:
<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 | The input channel over which the message is sent to the outbound channel adapter. |
2 | The JPA QL to execute.
This query may contain parameters that are evaluated by using the parameter element. |
3 | The entity manager used by the adapter to perform the JPA operations. |
4 | The elements (one for each parameter) used to define the value of the parameter names for the JPA QL specified in the query attribute. |
parameter
元素接受一个属性,其“名称”对应于在提供的 JPA QL 中指定的具名参数(在前面的示例中为第 2 点)。参数的值可以是静态的,也可以通过使用表达式来派生。静态值和用于派生值的表达式分别使用`value`和`expression`属性指定。这些属性互斥。
The parameter
element accepts an attribute whose name
corresponds to the named parameter specified in the provided JPA QL (point 2 in the preceding example).
The value of the parameter can either be static or be derived by using an expression.
The static value and the expression to derive the value are specified using the value
and expression
attributes, respectively.
These attributes are mutually exclusive.
如果指定了`value`属性,您可以提供一个可选的`type`属性。此属性的值是由`value`属性表示的值的完全限定类名。默认情况下,该类型假定为`java.lang.String`。以下示例演示了如何定义 JPA 参数:
If the value
attribute is specified, you 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
.
The following example shows how to define a JPA parameter:
<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 查询中指定的每个具名参数提供一个`parameter`元素。例如,我们指定两个参数:'level’和’name'。`level`属性是类型为`java.lang.Integer`的静态值,而`name`属性派生自消息的有效负载。
As the preceding example shows, you can use multiple parameter
elements within an outbound channel adapter element and define some parameters by using expressions and others with static values.
However, take care not to specify the same parameter name multiple times.
You should provide one parameter
element for each named parameter specified in the JPA query.
For example, we specify two parameters: level
and name
.
The level
attribute is a static value of type java.lang.Integer
, while the name
attribute is derived from the payload of the message.
尽管为 JPA QL 指定 |
Though specifying |
Using Native Queries
本节介绍了如何使用原生命令来使用 JPA 输出通道适配器执行操作。使用原生命令类似于使用 JPA QL,只是查询是本机数据库查询。通过使用原生命令,我们会失去 JPA QL 提供的数据库供应商独立性。
This section describes how to use native queries to perform operations with the JPA outbound channel adapter. Using native queries is similar to using JPA QL, except that the queries are native database queries. By using native queries, we lose database vendor independence, which we get using JPA QL.
通过使用原生查询,我们可以实现的事情之一是执行数据库插入,这是 JPA QL 办不到的。(要执行插入,我们会将 JPA 实体发送到通道适配器,就像 described earlier)。以下是演示如何使用原生查询在表中插入值的一个小 XML 片段。
One of the things we can achieve by using native queries is to perform database inserts, which is not possible with JPA QL. (To perform inserts, we send JPA entities to the channel adapter, as described earlier). Below is a small xml fragment that demonstrates the use of native query to insert values in a table.
你的 JPA 提供器可能不支持命名的参数与本机 SQL 查询结合使用。虽然它们在 Hibernate 中工作良好,但 OpenJPA 和 EclipseLink 不支持它们。请参阅 [role="bare"][role="bare"]https://issues.apache.org/jira/browse/OPENJPA-111. JPA 2.0 规范的 3.8.12 节规定:“Only positional parameter binding and positional access to result items may be portably used for native queries.”
Named parameters may not be supported by your JPA provider in conjunction with native SQL queries. While they work fine with Hibernate, OpenJPA and EclipseLink do not support them. See [role="bare"]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.”
以下示例使用原生命令配置输出通道适配器:
The following example configures an outbound-channel-adapter with a native query:
<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 | The native query executed by this outbound channel adapter. |
请注意,其他属性(例如`channel`和`entity-manager`)和`parameter`元素与用于 JPA QL 的语义相同。
Note that the other attributes (such as channel
and entity-manager
) and the parameter
element have the same semantics as they do for JPA QL.
Using Named Queries
使用命名查询类似于使用 JPA QL 或 native query,除了我们指定的是命名查询,而不是查询。首先,我们将介绍如何定义 JPA 命名查询。然后,我们将介绍如何声明一个出站通道适配器,使其能够使用一个命名查询。如果我们有一个名为 Student
的实体,我们可以对 Student
类使用注解,以定义两个命名查询: selectStudent
和 updateStudent
。以下示例展示如何执行此操作:
Using named queries is similar to using JPA QL or a native query, except that we specify a named query instead of a query.
First, we cover how to define a JPA named query.
Then we cover how to declare an outbound channel adapter to work with a named query.
If we have an entity called Student
, we can use annotations on the Student
class to define two named queries: selectStudent
and updateStudent
.
The following example shows how to do so:
@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 定义具名查询,如下面的示例所示:
Alternatively, you can use orm.xml to define named queries as the following example shows:
<entity-mappings ...>
...
<named-query name="selectStudent">
<query>select s from Student s where s.lastName = 'Last One'</query>
</named-query>
</entity-mappings>
现在我们已经通过使用注释或使用`orm.xml`演示了如何定义具名查询,我们现在展示一个小的 XML 片段,它使用具名查询定义`outbound-channel-adapter`,如下面的示例所示:
Now that we have shown how to define named queries by using annotations or by using orm.xml
, we now show a small XML fragment that defines an outbound-channel-adapter
by using a named query, as the following example shows:
<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 | The named query that we want the adapter to execute when it receives a message over the channel. |
Configuration Parameter Reference
以下清单显示了可以在输出通道适配器上设置的所有属性:
The following listing shows all the attributes that you can set on an outbound channel adapter:
<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 | Lifecycle attribute signaling whether this component should start during application context startup.
It defaults to true .
Optional. |
2 | The channel from which the outbound adapter receives messages for performing the desired operation. |
3 | The fully qualified name of the entity class for the JPA Operation.
The entity-class , query , and named-query attributes are mutually exclusive.
Optional. |
4 | An instance of jakarta.persistence.EntityManager used to perform the JPA operations.
Optional. |
5 | An instance of jakarta.persistence.EntityManagerFactory used to obtain an instance of jakarta.persistence.EntityManager , which performs the JPA operations.
Optional. |
6 | An implementation of org.springframework.integration.jpa.core.JpaOperations used to perform the JPA operations.
We recommend not providing an implementation of your own but using the default org.springframework.integration.jpa.core.DefaultJpaOperations implementation.
You can use any one of the entity-manager , entity-manager-factory , or jpa-operations attributes.
Optional. |
7 | The JPA QL to be executed by this adapter. Optional. |
8 | The named query that needs to be executed by this adapter. Optional. |
9 | The native query to be executed by this adapter.
You can use any one of the jpa-query , named-query , or native-query attributes.
Optional. |
10 | The order for this consumer when multiple consumers are registered, thereby managing load-balancing and failover.
It defaults to Ordered.LOWEST_PRECEDENCE .
Optional. |
11 | An instance of o.s.i.jpa.support.parametersource.ParameterSourceFactory used to get an instance of o.s.i.jpa.support.parametersource.ParameterSource , which is used to resolve the values of the parameters in the query.
Ignored if you perform operations by using a JPA entity.
The parameter sub-elements are mutually exclusive with the parameter-source-factory attribute and must be configured on the provided ParameterSourceFactory .
Optional. |
12 | Accepts one of the following: PERSIST , MERGE , or DELETE .
Indicates the operation that the adapter needs to perform.
Relevant only if you use an entity for JPA operations.
Ignored if you provide JPA QL, a named query, or a native query.
It defaults to MERGE .
Optional.
As of Spring Integration 3.0, payloads to persist or merge can also be of type java.lang.Iterable .
In that case, each object returned by the Iterable is treated as an entity and persisted or merged by using the underlying EntityManager .
Null values returned by the iterator are ignored. |
13 | Set this value to true if you want to flush the persistence context immediately after persist, merge, or delete operations and do not want to rely on the flushMode of the EntityManager .
It defaults to false .
Applies only if you did not specify the flush-size attribute.
If this attribute is set to true , flush-size is implicitly set to 1 , if no other value configured it. |
14 | 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 do not want to rely on the flushMode of the EntityManager .
The default value is set to 0 , which means "'no flush'".
This attribute is geared towards messages with Iterable payloads.
For instance, if flush-size is set to 3 , then entityManager.flush() is called after every third entity.
Furthermore, entityManager.flush() is called once more after the entire loop.
If the 'flush-size' attribute specified with a value greater than '0', you need not configure the flush attribute. |
15 | Set this value to 'true' if you want to clear the persistence context immediately after each flush operation.
The attribute’s value is applied only if the flush attribute is set to true or if the flush-size attribute is set to a value greater than 0 . |
16 | If set to true , the payload of the message is used as a source for parameters.
If set to false , however, the entire Message is available as a source for parameters.
Optional. |
17 | Defines the transaction management attributes and the reference to the transaction manager to be used by the JPA adapter. Optional. |
18 | One or more parameter attributes — one for each parameter used in the query.
The value or expression is evaluated to compute the value of the parameter.
Optional. |
Configuring with Java Configuration
以下 Spring Boot 应用程序展示了如何使用 Java 配置出站适配器:
The following Spring Boot application shows an example of how to configure the outbound adapter with 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;
}
}
Configuring with the Java DSL
以下 Spring Boot 应用程序展示了一个如何使用 Java DSL 配置出站适配器的示例:
The following Spring Boot application shows an example of how to configure the outbound adapter with 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());
}
}