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 表包含以下记录。

Eid Ename Salary Deg
1201 Gopal 40000 Technical Manager
1202 Manisha 40000 Proof Reader
1203 Masthanvali 40000 Technical Writer
1204 Satish 30000 Technical Writer
1205 Krishna 30000 Technical Writer
1206 Kiran 35000 Proof Reader

com.tutorialspoint.eclipselink.service包下创建一个名为ScalarandAggregateFunctions.java的类,如下所示。

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 子句之后使用。

com.tutorialspoint.eclipselink.service包下创建一个名为BetweenAndLikeFunctions.java的类,如下所示:

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("	 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("	 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 中的用法相同,但它处理实体。 请遵循示例中的顺序。

com.tutorialspoint.eclipselink.service包下创建一个类Ordering.java,如下:

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("	 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 分开来改进代码组织。 它还传递查询参数,而不是动态地将文字嵌入到查询字符串中,从而提高查询效率。

首先,在com.tutorialspoint.eclipselink.entity包下名为Employee.java的Employee实体类中添加@NamedQuery注解,如下:

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 + "]";
   }
}

com.tutorialspoint.eclipselink.service包下创建一个名为NamedQueries.java的类,如下所示:

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("	 Employee Name :" + e.getEname( ));
      }
   }
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板中得到如下输出:

Employee ID :1204	 Employee Name :Satish

添加以上所有类后,包层次结构如下所示:

包层次结构

急切加载和延迟加载

JPA 的主要概念是在缓存内存中制作数据库的副本。 在与数据库进行事务处理时,首先它将影响重复数据,并且仅当使用实体管理器提交时,更改才会影响到数据库。

从数据库中获取记录有两种方法 - 急切获取和延迟获取。

急切获取

在使用主键查找记录的同时获取整个记录。

延迟获取

它检查可用性,如果存在则用主键通知它。 然后,如果您调用该实体的任何 getter 方法,它就会获取整个实体。

但是当您第一次尝试获取记录时,延迟获取是可能的。 这样,整个记录的副本就已经存储在高速缓存中。 就性能而言,延迟获取更可取。