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使用以下語句時:
  1. SELECT DISTINCT e FROM Employee1 e
  2. INNER JOIN FETCH e.tasks t
對應的Criteria API用法如下:
  1. @Test
  2. public void Criteria_InnerJoinFetch() {
  3. EntityManager em = emf.createEntityManager();
  4. CriteriaBuilder cb = em.getCriteriaBuilder();
  5. CriteriaQuery sql = cb.createQuery(Employee1.class);
  6. Root emp1 = sql.from(Employee1.class);
  7. Fetch task =
  8. emp1.fetch(Employee1_.tasks, JoinType.INNER);
  9. sql.select(emp1)
  10. .distinct(true);
  11. TypedQuery typedQuery = em.createQuery(sql);
  12. List resultList = typedQuery.getResultList();
  13. resultList.forEach(System.out::println);
  14. assertThat(resultList,
  15. containsInAnyOrder(employee1, employee2, employee3));
  16. assertThat(resultList, hasSize(3));
  17. assertEquals(1, keyWordCount(out.getLog(), "Hibernate:"));
  18. }
  • 行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使用以下語句時:
  1. SELECT DISTINCT e FROM Employee1 e
  2. LEFT JOIN FETCH e.tasks t
對應的Criteria API用法如下。注意行8使用fetch()方法並指定聯結型態為JoinType.LEFT:
  1. @Test
  2. public void Criteria_LeftJoinFetch() {
  3. EntityManager em = emf.createEntityManager();
  4. CriteriaBuilder cb = em.getCriteriaBuilder();
  5. CriteriaQuery sql = cb.createQuery(Employee1.class);
  6. Root emp1 = sql.from(Employee1.class);
  7. Fetch task =
  8. emp1.fetch(Employee1_.tasks, JoinType.LEFT);
  9. sql.select(emp1)
  10. .distinct(true);
  11. TypedQuery typedQuery = em.createQuery(sql);
  12. List resultList = typedQuery.getResultList();
  13. resultList.forEach(System.out::println);
  14. assertThat(resultList,
  15. containsInAnyOrder(employee1, employee2, employee3, employee4));
  16. assertThat(resultList, hasSize(4));
  17. assertEquals(1, keyWordCount(out.getLog(), "Hibernate:"));
  18. }

沒有留言:

張貼留言