对于最新的稳定版本,请使用 Spring Integration 6.5.1spring-doc.cadn.net.cn

出站通道适配器

JPA 出站通道适配器允许您通过请求通道接受消息。有效负载可以用作要持久化的实体,也可以与 JPQL 查询的参数表达式中的标头一起使用。以下部分介绍了执行这些作的可能方法。spring-doc.cadn.net.cn

使用实体类

以下 XML 将出站通道适配器配置为将实体持久化到数据库:spring-doc.cadn.net.cn

<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,MERGEDELETE. 默认值为MERGE.
4 要使用的 JPA 实体管理器。

的这四个属性outbound-channel-adapter将其配置为通过输入通道接受实体,并将它们处理为PERSIST,MERGEDELETE基础数据源中的实体。spring-doc.cadn.net.cn

从 Spring Integration 3.0 开始,有效负载PERSISTMERGE也可以是类型java.lang.Iterable. 在这种情况下,每个对象返回的Iterable被视为实体,并使用基础EntityManager. 迭代器返回的 Null 值将被忽略。
从 5.5.4 版本开始,JpaOutboundGateway,带有JpaExecutor配置为PersistMode.DELETE,可以接受Iterable有效负载,以对提供的实体执行批量删除持久性作。

使用 JPA 查询语言 (JPA QL)

上一节展示了如何执行PERSIST使用实体进行作。本节介绍如何将出站通道适配器与 JPA QL 一起使用。spring-doc.cadn.net.cn

以下 XML 将出站通道适配器配置为将实体持久化到数据库:spring-doc.cadn.net.cn

<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 用于定义 JPA QL 的参数名称值的元素(每个参数一个)在query属性。

parameter元素接受一个属性,其name对应于提供的 JPA QL 中指定的命名参数(前面示例中的第 2 点)。参数的值可以是静态的,也可以是使用表达式派生的。静态值和派生值的表达式是使用valueexpression属性。这些属性是互斥的。spring-doc.cadn.net.cn

如果value属性,则可以提供可选的type属性。 此属性的值是类的完全限定名称,其值由value属性。 默认情况下,类型假定为java.lang.String. 以下示例显示了如何定义 JPA 参数:spring-doc.cadn.net.cn

<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出站通道适配器元素中的元素,并使用表达式定义一些参数,而其他参数则具有静态值。但是,请注意不要多次指定相同的参数名称。应提供一个parameter元素。例如,我们指定两个参数:levelname. 这level属性是类型java.lang.Integer,而name属性派生自消息的有效负载。spring-doc.cadn.net.cn

虽然指定select对 JPA QL 有效,这样做是没有意义的。 出站通道适配器不返回任何结果。 如果要选择某些值,请考虑改用出站网关。

使用本机查询

本节介绍如何使用本机查询对 JPA 出站通道适配器执行作。 使用本机查询类似于使用 JPA QL,不同之处在于查询是本机数据库查询。 通过使用本机查询,我们失去了数据库提供商的独立性,这是我们使用 JPA QL 获得的。spring-doc.cadn.net.cn

通过使用本机查询,我们可以实现的一件事是执行数据库插入,这在 JPA QL 中是不可能的。 (为了执行插入,我们将 JPA 实体发送到通道适配器,如前所述)。 下面是一个小的 xml 片段,演示了如何使用本机查询在表中插入值。spring-doc.cadn.net.cn

您的 JPA 提供程序可能不支持与本机 SQL 查询结合使用的命名参数。 虽然它们与 Hibernate 一起工作得很好,但 OpenJPA 和 EclipseLink 不支持它们。 见 issues.apache.org/jira/browse/OPENJPA-111。 JPA 2.0 规范的第 3.8.12 节规定:“只有位置参数绑定和对结果项的位置访问才能移植地用于本机查询。

以下示例使用本机查询配置 outbound-channel-adapter:spring-doc.cadn.net.cn

<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 此出站通道适配器执行的本机查询。

请注意,其他属性(例如channelentity-manager) 和parameter元素具有与 JPA QL 相同的语义。spring-doc.cadn.net.cn

使用命名查询

使用命名查询类似于使用 JPA QL本机查询,不同之处在于我们指定了命名查询而不是查询。 首先,我们介绍如何定义 JPA 命名查询。 然后,我们将介绍如何声明出站通道适配器以使用命名查询。 如果我们有一个名为Student,我们可以在Studentclass 来定义两个命名查询:selectStudentupdateStudent. 以下示例显示了如何执行此作:spring-doc.cadn.net.cn

@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来定义命名查询,如以下示例所示:spring-doc.cadn.net.cn

<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使用命名查询,如以下示例所示:spring-doc.cadn.net.cn

<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 我们希望适配器在通过通道接收消息时执行的命名查询。

配置参数参考

以下列表显示了可以在出站通道适配器上设置的所有属性:spring-doc.cadn.net.cn

<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,querynamed-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-factoryjpa-operations属性。 自选。
7 要由此适配器执行的 JPA QL。 自选。
8 此适配器需要执行的命名查询。 自选。
9 此适配器要执行的本机查询。 您可以使用jpa-query,named-querynative-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,MERGEDELETE. 指示适配器需要执行的作。 仅当您将实体用于 JPA作时才相关。 如果您提供 JPA QL、命名查询或本机查询,则忽略。 它默认为MERGE. 自选。 从 Spring Integration 3.0 开始,要持久化或合并的有效负载也可以是java.lang.Iterable. 在这种情况下,每个对象返回的Iterable被视为实体,并使用基础EntityManager. 迭代器返回的 Null 值将被忽略。
13 将此值设置为true如果要在持久化、合并或删除作后立即刷新持久性上下文,并且不想依赖flushModeEntityManager. 它默认为false. 仅当您未指定flush-size属性。 如果此属性设置为true,flush-size隐式设置为1,如果没有其他值配置它。
14 如果要在持久化、合并或删除作后立即刷新持久性上下文,并且不想依赖flushModeEntityManager. 默认值设置为0,意思是“'没有冲水'”。 此属性适用于Iterable负载。 例如,如果flush-size设置为3然后entityManager.flush()每三个实体之后调用一次。 此外entityManager.flush()在整个循环之后再次调用。 如果指定的值大于“0”的“flush-size”属性,则无需配置flush属性。
15 如果要在每次刷新作后立即清除持久性上下文,请将此值设置为“true”。 仅当flush属性设置为true或者如果flush-size属性设置为大于0.
16 如果设置为true,则消息的有效负载用作参数的源。 如果设置为false然而,整个Message可用作参数的源。 自选。
17 定义事务管理属性和对 JPA 适配器要使用的事务管理器的引用。 自选。
18 一个或多个parameterattributes — 查询中使用的每个参数一个。 计算值或表达式以计算参数的值。 自选。

使用 Java 配置进行配置

以下 Spring Boot 应用程序显示了如何使用 Java 配置出站适配器的示例:spring-doc.cadn.net.cn

@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 配置出站适配器的示例:spring-doc.cadn.net.cn

@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());
    }

}