- JPA 教程
- JPA - 首页
- JPA - 简介
- JPA - 架构
- JPA - ORM组件
- JPA - 安装
- JPA - 实体管理器
- JPA - JPQL
- JPA - 高级映射
- JPA - 实体关系
- JPA - Criteria API
- JPA 有用资源
- JPA - 快速指南
- JPA - 有用资源
JPA - JPQL
本章介绍 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
添加所有上述类后,包层次结构如下所示:
急切加载和延迟加载
JPA 的主要概念是在缓存内存中创建数据库的副本。在与数据库进行事务处理时,它首先会影响重复数据,只有当使用实体管理器提交更改时,更改才会影响数据库。
有两种从数据库中提取记录的方法:急切提取和延迟提取。
急切提取
使用主键查找记录时提取整个记录。
延迟提取
它检查是否存在并使用主键通知它。然后,如果您调用该实体的任何 getter 方法,它将提取全部内容。
但是,只有在您第一次尝试提取记录时才有可能进行延迟提取。这样,整个记录的副本就已经存储在缓存内存中了。从性能角度来看,延迟提取更可取。