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 方法,它将提取全部内容。

但是,只有在您第一次尝试提取记录时才有可能进行延迟提取。这样,整个记录的副本就已经存储在缓存内存中了。从性能角度来看,延迟提取更可取。

广告