- 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 方法,它将提取全部内容。
但是,只有在您第一次尝试提取记录时才有可能进行延迟提取。这样,整个记录的副本就已经存储在缓存内存中了。从性能角度来看,延迟提取更可取。