2020年5月23日 星期六

FETCH JOIN


本文為【Spring Boot情境式網站開發指南:使用Spring Data JPA、Spring Security、Spring Web Flow】一書的【 第4章 Criteria API入門】延續,完整範例程式碼可至出版社下載

「FETCH」敘述可用於JOIN,如INNER JOIN或LEFT JOIN,可以在一次查詢中獲取全部關聯實體的資料,不需再依個別Entity的關聯而逐筆執行查詢。

INNER JOIN FETCH

當JPQL使用以下語句時:
SELECT DISTINCT e FROM Employee1 e 
                  INNER JOIN FETCH e.tasks t
對應的Criteria API用法如下:
@Test
public void Criteria_InnerJoinFetch() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Employee1.class);
    Root emp1 = sql.from(Employee1.class);
    Fetch task =  
            emp1.fetch(Employee1_.tasks, JoinType.INNER);
    sql.select(emp1)
        .distinct(true);
    TypedQuery typedQuery = em.createQuery(sql);
    List resultList = typedQuery.getResultList();
    resultList.forEach(System.out::println);
    assertThat(resultList, 
            containsInAnyOrder(employee1, employee2, employee3));
    assertThat(resultList, hasSize(3));
    assertEquals(1, keyWordCount(out.getLog(), "Hibernate:"));
}
  • 行7-8
使用Root<Employee1> emp1的fetch()方法並指定:
1. 聯結「欄位」,本例為Employee1_.tasks。
2. 聯結「型態」,本例為JoinType.INNER。
可以得到Fetch<Employee1, Task>物件,和先前Join<Employee1, Task>物件參考相似。本例並無使用該物件參考,實際上並不需要特別宣告物件參考指向方法執行後的回傳結果,只是單純讓讀者了解fetch()方法回傳型態為Fetch物件。
  • 行9
使用sql.select(emp1)看似只查詢Employee1類別,但使用fetch()方法已經一次取回Employee1類別與其關聯的Task類別的所有欄位資料,因此呼叫emp1.getTasks()將可以直接由本地端JVM取得資料,不需要依賴
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Task> tasks;
的宣告逐筆至遠端資料庫中取回資料。優點是可以減少資料庫的shared lock狀況並提升效能,但必須衡量是否有需要這些資料,以及記憶體使用狀況。

LEFT JOIN FETCH

概念與INNER JOIN FETCH相同,只是改用LEFT JOIN。當JPQL使用以下語句時:
SELECT DISTINCT e FROM Employee1 e 
                  LEFT JOIN FETCH e.tasks t
對應的Criteria API用法如下。注意行8使用fetch()方法並指定聯結型態為JoinType.LEFT:
@Test
public void Criteria_LeftJoinFetch() {
    EntityManager em = emf.createEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery sql = cb.createQuery(Employee1.class);
    Root emp1 = sql.from(Employee1.class);
    Fetch task = 
            emp1.fetch(Employee1_.tasks, JoinType.LEFT);
    sql.select(emp1)
        .distinct(true);
    TypedQuery typedQuery = em.createQuery(sql);
    List resultList = typedQuery.getResultList();
    resultList.forEach(System.out::println);
    assertThat(resultList, 
         containsInAnyOrder(employee1, employee2, employee3, employee4));
    assertThat(resultList, hasSize(4));
    assertEquals(1, keyWordCount(out.getLog(), "Hibernate:"));
}

沒有留言:

張貼留言