出站通道适配器
JPA 出站通道适配器允许您通过请求通道接受消息。 有效负载可以用作要保留的实体,也可以与 JPQL 查询的参数表达式中的标头一起使用。 以下部分介绍了执行这些作的可能方法。
使用 Entity 类
以下 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
将其配置为通过 Input Channel 接受实体并将其处理为PERSIST
,MERGE
或DELETE
来自基础数据源的实体。
从 Spring Integration 3.0 开始,payloads 到PERSIST 或MERGE 也可以是 typejava.lang.Iterable .
在这种情况下,由Iterable 被视为实体,并使用底层EntityManager .
迭代器返回的 Null 值将被忽略。 |
从版本 5.5.4 开始,JpaOutboundGateway ,其中JpaExecutor 配置了PersistMode.DELETE 可以接受Iterable payload 对提供的实体执行批量删除持久作。 |
使用 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 | 将消息发送到出站通道适配器的 input 通道。 |
2 | 要执行的 JPA QL。
此查询可能包含使用parameter 元素。 |
3 | 适配器用于执行 JPA作的实体管理器。 |
4 | 用于定义 JPA QL 的参数名称值的元素(每个参数一个)query 属性。 |
这parameter
元素接受一个属性,该属性的name
对应于提供的 JPA QL 中指定的命名参数(前面示例中的第 2 点)。
参数的值可以是 static,也可以是使用表达式派生的。
static 值和派生值的表达式是使用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
元素,并使用表达式定义一些参数,并使用 Expressions 和其他具有 static 值的参数。
但是,请注意不要多次指定相同的参数名称。
您应该提供一个parameter
元素。
例如,我们指定两个参数:level
和name
.
这level
attribute 是java.lang.Integer
,而name
属性派生自消息的有效负载。
虽然指定select 对 JPA QL 有效,则这样做没有意义。
出站通道适配器不返回任何结果。
如果要选择一些值,请考虑改用出站网关。 |
使用本机查询
本节介绍如何使用本机查询对 JPA 出站通道适配器执行作。 使用本机查询与使用 JPA QL 类似,不同之处在于查询是本机数据库查询。 通过使用本机查询,我们失去了使用 JPA QL 获得的数据库供应商独立性。
通过使用本机查询,我们可以实现的一件事是执行数据库插入,这在 JPA QL 中是不可能的。 (为了执行插入,我们将 JPA 实体发送到通道适配器,如前所述)。 下面是一个小的 xml 片段,它演示了如何使用本机查询在表中插入值。
您的 JPA 提供程序可能不支持将命名参数与本机 SQL 查询结合使用。 虽然它们与 Hibernate 一起工作良好,但 OpenJPA 和 EclipseLink 不支持它们。 请参阅 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
类来定义两个命名查询: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
,我们现在显示一个小的 XML 片段,它定义了一个outbound-channel-adapter
通过使用命名查询,如下例所示:
<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 Operation 的实体类的完全限定名称。
这entity-class ,query 和named-query 属性是互斥的。
自选。 |
4 | 一个jakarta.persistence.EntityManager 用于执行 JPA作。
自选。 |
5 | 一个jakarta.persistence.EntityManagerFactory 用于获取jakarta.persistence.EntityManager 执行 JPA作。
自选。 |
6 | 的实现org.springframework.integration.jpa.core.JpaOperations 用于执行 JPA作。
我们建议不要提供您自己的实现,而是使用默认的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.ParameterSourceFactory 用于获取o.s.i.jpa.support.parametersource.ParameterSource ,用于解析查询中参数的值。
如果您使用 JPA 实体执行作,则忽略。
这parameter 子元素与parameter-source-factory 属性,并且必须在提供的ParameterSourceFactory .
自选。 |
12 | 接受以下选项之一:PERSIST ,MERGE 或DELETE .
指示适配器需要执行的作。
仅当您将实体用于 JPA作时才相关。
如果您提供 JPA QL、命名查询或本机查询,则忽略。
它默认为MERGE .
自选。
从 Spring Integration 3.0 开始,要持久化或合并的有效负载也可以是 typejava.lang.Iterable .
在这种情况下,由Iterable 被视为实体,并使用底层EntityManager .
迭代器返回的 Null 值将被忽略。 |
13 | 将此值设置为true 如果您想在 persist、merge 或 delete作后立即刷新持久性上下文,并且不想依赖flushMode 的EntityManager .
它默认为false .
仅在未指定flush-size 属性。
如果此属性设置为true ,flush-size 隐式设置为1 ,如果没有其他值配置它。 |
14 | 如果要在 persist、merge 或 delete作后立即刷新持久性上下文,并且不想依赖flushMode 的EntityManager .
默认值设置为0 ,意思是 “'no flush'”。
此属性适用于具有以下Iterable 负载。
例如,如果flush-size 设置为3 然后entityManager.flush() 在每三个实体之后调用。
此外entityManager.flush() 在整个循环后再次调用。
如果指定的 'flush-size' 属性的值大于 '0',则无需配置flush 属性。 |
15 | 如果要在每次刷新作后立即清除持久性上下文,请将此值设置为 'true'。
仅当flush 属性设置为true 或者,如果flush-size 属性设置为大于0 . |
16 | 如果设置为true ,则消息的有效负载将用作参数的源。
如果设置为false ,但是,整个Message 可用作参数的源。
自选。 |
17 | 定义事务管理属性和对 JPA 适配器要使用的事务管理器的引用。 自选。 |
18 | 一个或多个parameter attributes — 查询中使用的每个参数一个。
计算值或表达式以计算参数的值。
自选。 |
使用 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());
}
}