对于最新的稳定版本,请使用 Spring Integration 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Integration 6.3.1Spring中文文档

JPA 出站通道适配器允许您通过请求通道接受消息。 有效负载既可以用作要保留的实体,也可以与 JPQL 查询的参数表达式中的标头一起使用。 以下各节介绍了执行这些操作的可能方法。Spring中文文档

使用实体类

以下 XML 将出站通道适配器配置为将实体保存到数据库中:Spring中文文档

<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 适配器要执行的操作。 有效值为 、 和 。 默认值为 。PERSISTMERGEDELETEMERGE
4 要使用的 JPA 实体管理器。

的这四个属性将其配置为通过输入通道接受实体,并将它们处理为 、 或基础数据源中的实体。outbound-channel-adapterPERSISTMERGEDELETESpring中文文档

从 Spring Integration 3.0 开始,有效负载 或 也可以是 类型。 在这种情况下,返回的每个对象都被视为一个实体,并使用基础 . 迭代器返回的 Null 值将被忽略。PERSISTMERGEjava.lang.IterableIterableEntityManager
从版本 5.5.4 开始,配置了 的 可以接受有效负载,以便对提供的实体执行批量删除持久操作。JpaOutboundGatewayJpaExecutorPersistMode.DELETEIterable
1 将有效 JPA 实体发送到 JPA 出站通道适配器的通道。
2 适配器接受的要保留在数据库中的实体类的完全限定名称。 在大多数情况下,您实际上可以省略此属性,因为适配器可以从 Spring Integration 消息有效负载中自动确定实体类。
3 适配器要执行的操作。 有效值为 、 和 。 默认值为 。PERSISTMERGEDELETEMERGE
4 要使用的 JPA 实体管理器。
从 Spring Integration 3.0 开始,有效负载 或 也可以是 类型。 在这种情况下,返回的每个对象都被视为一个实体,并使用基础 . 迭代器返回的 Null 值将被忽略。PERSISTMERGEjava.lang.IterableIterableEntityManager
从版本 5.5.4 开始,配置了 的 可以接受有效负载,以便对提供的实体执行批量删除持久操作。JpaOutboundGatewayJpaExecutorPersistMode.DELETEIterable

使用 JPA 查询语言 (JPA QL)

上一节演示了如何使用实体执行操作。 本节介绍如何将出站通道适配器与 JPA QL 配合使用。PERSISTSpring中文文档

以下 XML 将出站通道适配器配置为将实体保存到数据库中:Spring中文文档

<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

该元素接受一个属性,该属性对应于提供的 JPA QL 中指定的命名参数(前面示例中的第 2 点)。 参数的值可以是静态的,也可以是使用表达式派生的。 静态值和派生值的表达式分别使用 和 属性指定。 这些属性是互斥的。parameternamevalueexpressionSpring中文文档

如果指定了该属性,则可以提供可选属性。 此属性的值是类的完全限定名称,其值由该属性表示。 默认情况下,类型假定为 . 以下示例说明如何定义 JPA 参数:valuetypevaluejava.lang.StringSpring中文文档

<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>

如前面的示例所示,您可以在出站通道适配器元素中使用多个元素,并使用表达式定义某些参数,并使用静态值定义其他参数。 但是,请注意不要多次指定相同的参数名称。 您应该为 JPA 查询中指定的每个命名参数提供一个元素。 例如,我们指定两个参数:和 。 该属性是 类型的静态值,而该属性派生自消息的有效负载。parameterparameterlevelnameleveljava.lang.IntegernameSpring中文文档

尽管指定对 JPA QL 有效,但这样做毫无意义。 出站通道适配器不返回任何结果。 如果要选择某些值,请考虑改用出站网关。select
1 将消息发送到出站通道适配器的输入通道。
2 要执行的 JPA QL。 此查询可能包含使用元素计算的参数。parameter
3 适配器用于执行 JPA 操作的实体管理器。
4 用于定义属性中指定的 JPA QL 的参数名称值的元素(每个参数一个)。query
尽管指定对 JPA QL 有效,但这样做毫无意义。 出站通道适配器不返回任何结果。 如果要选择某些值,请考虑改用出站网关。select

使用本机查询

本节介绍如何使用本机查询对 JPA 出站通道适配器执行操作。 使用本机查询与使用 JPA QL 类似,只是查询是本机数据库查询。 通过使用本机查询,我们失去了数据库供应商的独立性,而我们使用 JPA QL 获得了这种独立性。Spring中文文档

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

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

以下示例使用本机查询配置出站通道适配器:Spring中文文档

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

请注意,其他属性(如 和 )和元素的语义与 JPA QL 的语义相同。channelentity-managerparameterSpring中文文档

您的 JPA 提供程序可能不支持命名参数和本机 SQL 查询。 虽然它们在 Hibernate 上工作正常,但 OpenJPA 和 EclipseLink 不支持它们。 请参见 issues.apache.org/jira/browse/OPENJPA-111。 JPA 2.0 规范的第 3.8.12 节指出:“只有位置参数绑定和对结果项的位置访问可以可移植地用于本机查询。
1 此出站通道适配器执行的本机查询。

使用命名查询

使用命名查询类似于使用 JPA QL本机查询,只不过我们指定的是命名查询而不是查询。 首先,我们将介绍如何定义 JPA 命名查询。 然后,我们将介绍如何声明出站通道适配器以使用命名查询。 如果我们有一个名为 的实体,我们可以在类上使用注释来定义两个命名查询: 和 。 以下示例演示如何执行此操作:StudentStudentselectStudentupdateStudentSpring中文文档

@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中文文档

<entity-mappings ...>
    ...
    <named-query name="selectStudent">
        <query>select s from Student s where s.lastName = 'Last One'</query>
    </named-query>
</entity-mappings>

现在,我们已经展示了如何使用批注或使用 来定义命名查询,现在我们展示了一个小型 XML 片段,该片段使用命名查询定义 ,如以下示例所示:orm.xmloutbound-channel-adapterSpring中文文档

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

配置参数参考

以下清单显示了可以在出站通道适配器上设置的所有属性:Spring中文文档

<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-classquerynamed-query
4 用于执行 JPA 操作的实例。 自选。jakarta.persistence.EntityManager
5 用于获取 的实例,用于执行 JPA 操作的实例。 自选。jakarta.persistence.EntityManagerFactoryjakarta.persistence.EntityManager
6 用于执行 JPA 操作的实现。 我们建议不要提供自己的实现,而是使用默认实现。 可以使用 、 或 属性中的任何一个。 自选。org.springframework.integration.jpa.core.JpaOperationsorg.springframework.integration.jpa.core.DefaultJpaOperationsentity-managerentity-manager-factoryjpa-operations
7 要由此适配器执行的 JPA QL。 自选。
8 此适配器需要执行的命名查询。 自选。
9 此适配器要执行的本机查询。 可以使用 、 或 属性中的任何一个。 自选。jpa-querynamed-querynative-query
10 注册多个使用者时此使用者的顺序,从而管理负载平衡和故障转移。 它默认为 。 自选。Ordered.LOWEST_PRECEDENCE
11 用于获取 的实例,用于解析查询中参数的值。 如果使用 JPA 实体执行操作,则忽略。 子元素与属性互斥,必须在提供的 上配置。 自选。o.s.i.jpa.support.parametersource.ParameterSourceFactoryo.s.i.jpa.support.parametersource.ParameterSourceparameterparameter-source-factoryParameterSourceFactory
12 接受下列选项之一:、 或 。 指示适配器需要执行的操作。 仅当将实体用于 JPA 操作时才相关。 如果提供 JPA QL、命名查询或本机查询,则忽略。 它默认为 。 自选。 从 Spring Integration 3.0 开始,要保留或合并的有效负载也可以是 类型。 在这种情况下,将 返回的每个对象视为一个实体,并使用基础 来保留或合并 。 迭代器返回的 Null 值将被忽略。PERSISTMERGEDELETEMERGEjava.lang.IterableIterableEntityManager
13 如果要在持久性、合并或删除操作后立即刷新持久性上下文,并且不想依赖 的 ,请将此值设置为 。 它默认为 。 仅当未指定属性时才适用。 如果此属性设置为 ,则隐式设置为 ,如果没有其他值配置它。trueflushModeEntityManagerfalseflush-sizetrueflush-size1
14 如果要在执行持久性、合并或删除操作后立即刷新持久性上下文,并且不想依赖 的 。 默认值设置为 ,表示“'no flush'”。 此属性面向具有有效负载的消息。 例如,if 设置为 ,则在每三个实体之后调用。 此外,在整个循环之后再次调用。 如果指定的“flush-size”属性的值大于“0”,则无需配置该属性。flushModeEntityManager0Iterableflush-size3entityManager.flush()entityManager.flush()flush
15 如果要在每次刷新操作后立即清除持久性上下文,请将此值设置为“true”。 仅当属性设置为 或属性设置为大于 的值时,才会应用属性的值。flushtrueflush-size0
16 如果设置为 ,则消息的有效负载将用作参数的源。 但是,如果设置为 ,则 whole 可用作参数的源。 自选。truefalseMessage
17 定义事务管理属性和对 JPA 适配器要使用的事务管理器的引用。 自选。
18 一个或多个属性 — 查询中使用的每个参数对应一个属性。 计算值或表达式以计算参数的值。 自选。parameter
1 生命周期属性指示此组件是否应在应用程序上下文启动期间启动。 它默认为 。 自选。true
2 出站适配器从中接收消息以执行所需操作的通道。
3 JPA 操作的实体类的完全限定名称。 、 和 属性是互斥的。 自选。entity-classquerynamed-query
4 用于执行 JPA 操作的实例。 自选。jakarta.persistence.EntityManager
5 用于获取 的实例,用于执行 JPA 操作的实例。 自选。jakarta.persistence.EntityManagerFactoryjakarta.persistence.EntityManager
6 用于执行 JPA 操作的实现。 我们建议不要提供自己的实现,而是使用默认实现。 可以使用 、 或 属性中的任何一个。 自选。org.springframework.integration.jpa.core.JpaOperationsorg.springframework.integration.jpa.core.DefaultJpaOperationsentity-managerentity-manager-factoryjpa-operations
7 要由此适配器执行的 JPA QL。 自选。
8 此适配器需要执行的命名查询。 自选。
9 此适配器要执行的本机查询。 可以使用 、 或 属性中的任何一个。 自选。jpa-querynamed-querynative-query
10 注册多个使用者时此使用者的顺序,从而管理负载平衡和故障转移。 它默认为 。 自选。Ordered.LOWEST_PRECEDENCE
11 用于获取 的实例,用于解析查询中参数的值。 如果使用 JPA 实体执行操作,则忽略。 子元素与属性互斥,必须在提供的 上配置。 自选。o.s.i.jpa.support.parametersource.ParameterSourceFactoryo.s.i.jpa.support.parametersource.ParameterSourceparameterparameter-source-factoryParameterSourceFactory
12 接受下列选项之一:、 或 。 指示适配器需要执行的操作。 仅当将实体用于 JPA 操作时才相关。 如果提供 JPA QL、命名查询或本机查询,则忽略。 它默认为 。 自选。 从 Spring Integration 3.0 开始,要保留或合并的有效负载也可以是 类型。 在这种情况下,将 返回的每个对象视为一个实体,并使用基础 来保留或合并 。 迭代器返回的 Null 值将被忽略。PERSISTMERGEDELETEMERGEjava.lang.IterableIterableEntityManager
13 如果要在持久性、合并或删除操作后立即刷新持久性上下文,并且不想依赖 的 ,请将此值设置为 。 它默认为 。 仅当未指定属性时才适用。 如果此属性设置为 ,则隐式设置为 ,如果没有其他值配置它。trueflushModeEntityManagerfalseflush-sizetrueflush-size1
14 如果要在执行持久性、合并或删除操作后立即刷新持久性上下文,并且不想依赖 的 。 默认值设置为 ,表示“'no flush'”。 此属性面向具有有效负载的消息。 例如,if 设置为 ,则在每三个实体之后调用。 此外,在整个循环之后再次调用。 如果指定的“flush-size”属性的值大于“0”,则无需配置该属性。flushModeEntityManager0Iterableflush-size3entityManager.flush()entityManager.flush()flush
15 如果要在每次刷新操作后立即清除持久性上下文,请将此值设置为“true”。 仅当属性设置为 或属性设置为大于 的值时,才会应用属性的值。flushtrueflush-size0
16 如果设置为 ,则消息的有效负载将用作参数的源。 但是,如果设置为 ,则 whole 可用作参数的源。 自选。truefalseMessage
17 定义事务管理属性和对 JPA 适配器要使用的事务管理器的引用。 自选。
18 一个或多个属性 — 查询中使用的每个参数对应一个属性。 计算值或表达式以计算参数的值。 自选。parameter

使用 Java 配置进行配置

以下 Spring Boot 应用程序显示了如何使用 Java 配置出站适配器的示例:Spring中文文档

@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中文文档

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

}