JPA - JPQL



本章介紹 JPQL 及其與持久化單元的工作方式。本章中的示例遵循與上一章相同的包層次結構,如下所示:

JPA JPQL

Java 持久化查詢語言

JPQL 是 JPA 規範中定義的 Java 持久化查詢語言。它用於建立針對儲存在關係資料庫中的實體的查詢。JPQL 基於 SQL 語法開發。但它不會直接影響資料庫。

JPQL 可以使用 SELECT 子句檢索資訊或資料,可以使用 UPDATE 子句和 DELETE 子句進行批次更新。EntityManager.createQuery() API 將支援查詢語言。

查詢結構

JPQL 語法與 SQL 語法的語法非常相似。擁有類似 SQL 的語法是一個優勢,因為 SQL 是一種簡單的結構化查詢語言,許多開發人員都在應用程式中使用它。SQL 直接針對關係資料庫表、記錄和欄位工作,而 JPQL 與 Java 類和例項一起工作。

例如,JPQL 查詢可以檢索實體物件,而不是像 SQL 那樣從資料庫檢索欄位結果集。JPQL 查詢結構如下所示。

SELECT ... FROM ...
[WHERE ...]
[GROUP BY ... [HAVING ...]]
[ORDER BY ...]

JPQL DELETE 和 UPDATE 查詢的結構更簡單,如下所示。

DELETE FROM ... [WHERE ...]
 
UPDATE ... SET ... [WHERE ...]

標量和聚合函式

標量函式根據輸入值返回結果值。聚合函式透過計算輸入值來返回結果值。

遵循前面章節中使用的相同員工管理示例。在這裡,我們將學習使用 JPQL 的標量和聚合函式的服務類。

讓我們假設 jpadb.employee 表包含以下記錄。

員工ID(Eid) 員工姓名(Ename) 薪水(Salary) 職位(Deg)
1201 Gopal 40000 技術經理
1202 Manisha 40000 校對員
1203 Masthanvali 40000 技術撰寫人
1204 Satish 30000 技術撰寫人
1205 Krishna 30000 技術撰寫人
1206 Kiran 35000 校對員

建立一個名為 **ScalarandAggregateFunctions.java** 的類,放在 **com.tutorialspoint.eclipselink.service** 包下,如下所示。

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class ScalarandAggregateFunctions {
   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();

      //Scalar function
      Query query = entitymanager.
      createQuery("Select UPPER(e.ename) from Employee e");
      List<String> list = query.getResultList();

      for(String e:list) {
         System.out.println("Employee NAME :"+e);
      }
      
      //Aggregate function
      Query query1 = entitymanager.createQuery("Select MAX(e.salary) from Employee e");
      Double result = (Double) query1.getSingleResult();
      System.out.println("Max Employee Salary :" + result);
   }
}

編譯並執行上述程式後,您將在 Eclipse IDE 的控制檯面板中獲得如下輸出:

Employee NAME :GOPAL
Employee NAME :MANISHA
Employee NAME :MASTHANVALI
Employee NAME :SATISH
Employee NAME :KRISHNA
Employee NAME :KIRAN
ax Employee Salary :40000.0

Between、And、Like 關鍵字

“Between”、“And”和“Like”是 JPQL 的主要關鍵字。這些關鍵字在查詢中的 Where 子句之後使用。

建立一個名為 **BetweenAndLikeFunctions.java** 的類,放在 **com.tutorialspoint.eclipselink.service** 包下,如下所示。

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import com.tutorialspoint.eclipselink.entity.Employee;

public class BetweenAndLikeFunctions {
   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();
      
      //Between
      Query query = entitymanager.createQuery( "Select e " + "from Employee e " + "where e.salary " + "Between 30000 and 40000" );
      
      List<Employee> list=(List<Employee>)query.getResultList( );

      for( Employee e:list ){
         System.out.print("Employee ID :" + e.getEid( ));
         System.out.println("\t Employee salary :" + e.getSalary( ));
      }

      //Like
      Query query1 = entitymanager.createQuery("Select e " + "from Employee e " + "where e.ename LIKE 'M%'");
      
      List<Employee> list1=(List<Employee>)query1.getResultList( );
      
      for( Employee e:list1 ) {
         System.out.print("Employee ID :"+e.getEid( ));
         System.out.println("\t Employee name :"+e.getEname( ));
      }
   }
}

編譯並執行上述程式後,您將在 Eclipse IDE 的控制檯面板中獲得如下輸出:

Employee ID :1201	 Employee salary :40000.0
Employee ID :1202	 Employee salary :40000.0
Employee ID :1203	 Employee salary :40000.0
Employee ID :1204	 Employee salary :30000.0
Employee ID :1205	 Employee salary :30000.0
Employee ID :1206	 Employee salary :35000.0

Employee ID :1202	 Employee name :Manisha
Employee ID :1203	 Employee name :Masthanvali

排序

要在 JPQL 中對記錄進行排序,我們使用 ORDER BY 子句。此子句的用法與在 SQL 中的用法相同,但它處理的是實體。請遵循排序示例。

建立一個名為 **Ordering.java** 的類,放在 **com.tutorialspoint.eclipselink.service** 包下,如下所示。

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import com.tutorialspoint.eclipselink.entity.Employee;

public class Ordering {

   public static void main( String[ ] args ) {
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();
      
      //Between
      Query query = entitymanager.createQuery( "Select e " + "from Employee e " + "ORDER BY e.ename ASC" );

      List<Employee> list = (List<Employee>)query.getResultList( );

      for( Employee e:list ) {
         System.out.print("Employee ID :" + e.getEid( ));
         System.out.println("\t Employee Name :" + e.getEname( ));
      }
   }
}

編譯並執行上述程式後,您將在 Eclipse IDE 的控制檯面板中獲得如下輸出:

Employee ID :1201	 Employee Name :Gopal
Employee ID :1206	 Employee Name :Kiran
Employee ID :1205	 Employee Name :Krishna
Employee ID :1202	 Employee Name :Manisha
Employee ID :1203	 Employee Name :Masthanvali
Employee ID :1204	 Employee Name :Satish

命名查詢

@NamedQuery 註解定義為具有預定義不變查詢字串的查詢。與動態查詢相比,使用命名查詢可以透過將 JPQL 查詢字串與 POJO 分離來改進程式碼組織。它還會傳遞查詢引數,而不是將文字動態嵌入到查詢字串中,從而產生更高效的查詢。

首先,將 @NamedQuery 註解新增到名為 **Employee.java** 的 Employee 實體類中,該類位於 **com.tutorialspoint.eclipselink.entity** 包下,如下所示。

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table
@NamedQuery(query = "Select e from Employee e where e.eid = :id", name = "find employee by id")

public class Employee {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO) 	
   
   private int eid;
   private String ename;
   private double salary;
   private String deg;
   
   public Employee(int eid, String ename, double salary, String deg) {
      super( );
      this.eid = eid;
      this.ename = ename;
      this.salary = salary;
      this.deg = deg;
   }
   
   public Employee( ) {
      super();
   }

   public int getEid( ) {
      return eid;
   }
   
   public void setEid(int eid) {
      this.eid = eid;
   }

   public String getEname( ) {
      return ename;
   }
   
   public void setEname(String ename) {
      this.ename = ename;
   }

   public double getSalary( ) {
      return salary;
   }
   
   public void setSalary(double salary) {
      this.salary = salary;
   }

   public String getDeg( ) {
      return deg;
   }
   
   public void setDeg(String deg) {
      this.deg = deg;
   }
   
   @Override
   public String toString() {
      return "Employee [eid=" + eid + ", ename=" + ename + ", salary=" + salary + ", deg=" + deg + "]";
   }
}

建立一個名為 **NamedQueries.java** 的類,放在 **com.tutorialspoint.eclipselink.service** 包下,如下所示。

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import com.tutorialspoint.eclipselink.entity.Employee;

public class NamedQueries {
   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();
      Query query = entitymanager.createNamedQuery("find employee by id");
      
      query.setParameter("id", 1204);
      List<Employee> list = query.getResultList( );
      
      for( Employee e:list ){
         System.out.print("Employee ID :" + e.getEid( ));
         System.out.println("\t Employee Name :" + e.getEname( ));
      }
   }
}

編譯並執行上述程式後,您將在 Eclipse IDE 的控制檯面板中獲得如下輸出:

Employee ID :1204	 Employee Name :Satish

新增所有上述類後,包層次結構如下所示:

Package Hierarchy

急切載入和延遲載入

JPA 的主要概念是在快取記憶體中建立資料庫的副本。在與資料庫進行事務處理時,它首先會影響重複資料,只有當使用實體管理器提交更改時,更改才會影響資料庫。

有兩種從資料庫中提取記錄的方法:急切提取和延遲提取。

急切提取

使用主鍵查詢記錄時提取整個記錄。

延遲提取

它檢查是否存在並使用主鍵通知它。然後,如果您呼叫該實體的任何 getter 方法,它將提取全部內容。

但是,只有在您第一次嘗試提取記錄時才有可能進行延遲提取。這樣,整個記錄的副本就已經儲存在快取記憶體中了。從效能角度來看,延遲提取更可取。

廣告