出站通道介面卡

JPA 出站通道介面卡允許您透過請求通道接收訊息。有效負載可以作為要持久化的實體使用,也可以與引數表示式中的頭一起用於 JPQL 查詢。以下部分介紹了執行這些操作的可能方法。

使用實體類

以下 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 介面卡要執行的操作。有效值為 PERSISTMERGEDELETE。預設值為 MERGE
4 要使用的 JPA 實體管理器。

outbound-channel-adapter 的這四個屬性配置它以透過輸入通道接受實體,並處理它們以從底層資料來源中PERSISTMERGEDELETE 實體。

從 Spring Integration 3.0 開始,用於 PERSISTMERGE 的負載也可以是 java.lang.Iterable 型別。在這種情況下,Iterable 返回的每個物件都被視為一個實體,並使用底層 EntityManager 進行持久化或合併。迭代器返回的空值將被忽略。
從 5.5.4 版本開始,JpaOutboundGateway,配置了 PersistMode.DELETEJpaExecutor,可以接受 Iterable 負載來對提供的實體執行批次刪除持久化操作。

使用 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 訊息傳送到出站通道介面卡的輸入通道。
2 要執行的 JPA QL。此查詢可能包含使用 parameter 元素評估的引數。
3 介面卡用於執行 JPA 操作的實體管理器。
4 用於定義 query 屬性中指定的 JPA QL 的引數名稱的值的元素(每個引數一個)。

parameter 元素接受一個屬性,其 name 對應於提供的 JPA QL 中指定的命名引數(上例中的第 2 點)。引數的值可以是靜態的,也可以透過表示式派生。靜態值和派生值的表示式分別透過 valueexpression 屬性指定。這些屬性是互斥的。

如果指定了 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 元素,並透過表示式定義一些引數,另一些則使用靜態值。但是,請注意不要多次指定相同的引數名。您應該為 JPA 查詢中指定的每個命名引數提供一個 parameter 元素。例如,我們指定兩個引數:levelnamelevel 屬性是 java.lang.Integer 型別的靜態值,而 name 屬性是從訊息的有效負載中派生的。

儘管為 JPA QL 指定 select 是有效的,但這樣做沒有意義。出站通道介面卡不返回任何結果。如果您想選擇一些值,請考慮使用出站閘道器。

使用原生查詢

本節介紹如何使用原生查詢來執行 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 節指出:“只有位置引數繫結和結果項的位置訪問可以用於原生查詢。”

以下示例配置了一個帶有原生查詢的出站通道介面卡

<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 具有相同的語義。

使用命名查詢

使用命名查詢類似於使用 JPA QL原生查詢,不同之處在於我們指定的是命名查詢而不是查詢。首先,我們介紹如何定義 JPA 命名查詢。然後,我們介紹如何宣告一個出站通道介面卡以使用命名查詢。如果有一個名為 Student 的實體,我們可以在 Student 類上使用註解來定義兩個命名查詢:selectStudentupdateStudent。以下示例展示瞭如何實現

@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 操作的實體類的完全限定名。entity-classquerynamed-query 屬性是互斥的。可選。
4 用於執行 JPA 操作的 jakarta.persistence.EntityManager 例項。可選。
5 用於獲取 jakarta.persistence.EntityManager 例項(該例項執行 JPA 操作)的 jakarta.persistence.EntityManagerFactory 例項。可選。
6 用於執行 JPA 操作的 org.springframework.integration.jpa.core.JpaOperations 實現。我們建議不要提供您自己的實現,而是使用預設的 org.springframework.integration.jpa.core.DefaultJpaOperations 實現。您可以使用 entity-managerentity-manager-factoryjpa-operations 屬性中的任何一個。可選。
7 此介面卡要執行的 JPA QL。可選。
8 此介面卡需要執行的命名查詢。可選。
9 此介面卡要執行的原生查詢。您可以使用 jpa-querynamed-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 接受以下值之一:PERSISTMERGEDELETE。指示介面卡需要執行的操作。僅當您將實體用於 JPA 操作時才相關。如果您提供 JPA QL、命名查詢或原生查詢,則忽略。預設為 MERGE。可選。從 Spring Integration 3.0 開始,用於持久化或合併的負載也可以是 java.lang.Iterable 型別。在這種情況下,Iterable 返回的每個物件都被視為一個實體,並使用底層 EntityManager 進行持久化或合併。迭代器返回的空值將被忽略。
13 如果您希望在持久化、合併或刪除操作後立即重新整理持久化上下文,並且不希望依賴 EntityManagerflushMode,則將此值設定為 true。預設為 false。僅當您未指定 flush-size 屬性時適用。如果此屬性設定為 true,則 flush-size 將隱式設定為 1,如果沒有其他值配置它。
14 如果您希望在持久化、合併或刪除操作後立即重新整理持久化上下文,並且不希望依賴 EntityManagerflushMode,則將此屬性設定為大於 '0' 的值。預設值設定為 0,表示“不重新整理”。此屬性適用於帶有 Iterable 負載的訊息。例如,如果 flush-size 設定為 3,則在每第三個實體之後呼叫 entityManager.flush()。此外,在整個迴圈結束後還會再次呼叫 entityManager.flush()。如果 'flush-size' 屬性指定的值大於 '0',則無需配置 flush 屬性。
15 如果設定為“true”,則在每次重新整理操作後立即清除持久化上下文。此屬性的值僅在 flush 屬性設定為 trueflush-size 屬性設定為大於 0 的值時才適用。
16 如果設定為 true,則訊息的有效負載將用作引數的來源。但是,如果設定為 false,則整個 Message 都可用作引數的來源。可選。
17 定義事務管理屬性以及 JPA 介面卡要使用的事務管理器的引用。可選。
18 一個或多個 parameter 屬性 — 查詢中使用的每個引數對應一個。評估值或表示式以計算引數的值。可選。

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

}
© . This site is unofficial and not affiliated with VMware.