JPA 快速指南



JPA - 简介

任何企业应用程序都通过存储和检索大量数据来执行数据库操作。尽管有各种可用的存储管理技术,但应用程序开发人员通常难以高效地执行数据库操作。

通常,Java 开发人员使用大量代码或使用专有框架来与数据库交互,而使用 JPA,与数据库交互的负担大大减轻。它在对象模型(Java 程序)和关系模型(数据库程序)之间架起了一座桥梁。

关系模型和对象模型之间的不匹配

关系对象以表格格式表示,而对象模型以对象的互连图格式表示。在将对象模型从关系数据库中存储和检索时,由于以下原因会发生一些不匹配:

  • 粒度:对象模型比关系模型具有更高的粒度。

  • 子类型:并非所有类型的关系数据库都支持子类型(意味着继承)。

  • 标识:与对象模型一样,关系模型在编写相等性时不会公开标识。

  • 关联:关系模型在查看对象领域模型时无法确定多个关系。

  • 数据导航:对象网络中对象之间的数据导航在两种模型中是不同的。

什么是 JPA?

Java 持久性 API 是一组类和方法,用于将大量数据持久地存储到 Oracle 公司提供的数据库中。

在哪里使用 JPA?

为了减少编写关系对象管理代码的负担,程序员遵循“JPA 提供程序”框架,该框架允许轻松与数据库实例交互。此处所需的框架由 JPA 接管。

JPA

JPA 历史

早期版本的 EJB 使用 javax.ejb.EntityBean 接口定义了与业务逻辑层相结合的持久层。

  • 在引入 EJB 3.0 时,持久层被分离并指定为 JPA 1.0(Java 持久性 API)。该 API 的规范于 2006 年 5 月 11 日与 JAVA EE5 的规范一起发布,使用 JSR 220。

  • JPA 2.0 于 2009 年 12 月 10 日作为 Java 社区流程 JSR 317 的一部分与 JAVA EE6 的规范一起发布。

  • JPA 2.1 于 2013 年 4 月 22 日使用 JSR 338 与 JAVA EE7 的规范一起发布。

JPA 提供程序

JPA 是一个开源 API,因此 Oracle、Redhat、Eclipse 等各种企业供应商通过在其产品中添加 JPA 持久性特性来提供新产品。其中一些产品包括:

Hibernate、Eclipselink、Toplink、Spring Data JPA 等。

JPA - 架构

Java 持久性 API 是将业务实体作为关系实体存储的来源。它展示了如何将简单的旧 JAVA 对象 (POJO) 定义为实体,以及如何管理具有关系的实体。

类级别架构

下图显示了 JPA 的类级别架构。它显示了 JPA 的核心类和接口。

JPA Class Level Architecture

下表描述了上述架构中显示的每个单元。

单元 描述
EntityManagerFactory 这是 EntityManager 的工厂类。它创建和管理多个 EntityManager 实例。
EntityManager 它是一个接口,它管理对象的持久化操作。它像 Query 实例的工厂一样工作。
实体 实体是持久化对象,存储为数据库中的记录。
EntityTransaction 它与 EntityManager 具有一对一的关系。对于每个 EntityManager,操作由 EntityTransaction 类维护。
持久性 此类包含用于获取 EntityManagerFactory 实例的静态方法。
查询 此接口由每个 JPA 供应商实现,以获取满足条件的关系对象。

上述类和接口用于将实体作为记录存储到数据库中。它们通过减少程序员为将数据存储到数据库中编写代码的工作量来帮助程序员,以便他们可以专注于更重要的活动,例如编写将类与数据库表映射的代码。

JPA 类关系

在上图架构中,类和接口之间的关系属于 javax.persistence 包。下图显示了它们之间的关系。

JPA Class Relationships
  • EntityManagerFactory 和 EntityManager 之间的关系是一对多。它是一个针对 EntityManager 实例的工厂类。

  • EntityManager 和 EntityTransaction 之间的关系是一对一。对于每个 EntityManager 操作,都有一个 EntityTransaction 实例。

  • EntityManager 和 Query 之间的关系是一对多。可以使用一个 EntityManager 实例执行多个查询。

  • EntityManager 和 Entity 之间的关系是一对多。一个 EntityManager 实例可以管理多个实体。

JPA - ORM 组件

大多数当代应用程序使用关系数据库来存储数据。最近,许多供应商转向对象数据库以减轻数据维护的负担。这意味着对象数据库或对象关系技术负责存储、检索、更新和维护数据。此对象关系技术的核心部分是映射 orm.xml 文件。由于 xml 不需要编译,因此我们可以轻松地对多个数据源进行更改,而管理工作较少。

对象关系映射

对象关系映射 (ORM) 简要介绍了什么是 ORM 及其工作原理。ORM 是一种将数据从对象类型转换为关系类型并反之亦然的能力。

ORM 的主要功能是将对象与其在数据库中的数据映射或绑定。映射时,我们必须考虑数据、数据类型及其与自身实体或任何其他表中实体的关系。

高级特性

  • 惯用的持久性:它使您可以使用面向对象的类来编写持久性类。

  • 高性能:它具有许多获取技术和乐观的锁定技术。

  • 可靠性:它非常稳定,被许多专业程序员使用。

ORM 架构

ORM 架构如下所示。

Object Relational Mapping

上述架构解释了如何在三个阶段将对象数据存储到关系数据库中。

阶段 1

第一阶段,称为对象数据阶段,包含 POJO 类、服务接口和类。它是主要的业务组件层,具有业务逻辑操作和属性。

例如,让我们以员工数据库为模式。

  • Employee POJO 类包含 ID、姓名、工资和职位等属性。它还包含这些属性的 setter 和 getter 方法。

  • Employee DAO/Service 类包含服务方法,例如创建员工、查找员工和删除员工。

阶段 2

第二阶段,称为映射持久性阶段,包含 JPA 提供程序、映射文件 (ORM.xml)、JPA 加载程序和对象网格。

  • JPA 提供程序:它是包含 JPA 特性 (javax.persistence) 的供应商产品。例如 Eclipselink、Toplink、Hibernate 等。

  • 映射文件:映射文件 (ORM.xml) 包含 POJO 类中的数据和关系数据库中的数据之间的映射配置。

  • JPA 加载程序:JPA 加载程序像缓存内存一样工作。它可以加载关系网格数据。它就像数据库的副本,可以与服务类交互以获取 POJO 数据(POJO 类的属性)。

  • 对象网格:它是一个临时位置,可以存储关系数据的副本,就像缓存内存一样。所有针对数据库的查询首先都会对对象网格中的数据起作用。只有在提交后,它才会影响主数据库。

阶段 3

第三阶段是关系数据阶段。它包含与业务组件逻辑连接的关系数据。如上所述,只有当业务组件提交数据时,它才会物理地存储到数据库中。在此之前,修改后的数据将以网格格式存储在缓存内存中。获取数据的过程与存储数据的过程相同。

上述三个阶段的编程交互机制称为对象关系映射

Mapping.xml

mapping.xml 文件用于指示 JPA 提供程序将实体类与数据库表映射。

让我们以包含四个属性的 Employee 实体为例。名为Employee.java的 Employee 实体 POJO 类如下所示

public class Employee 
{
	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;
	}
}

以上代码是 Employee 实体 POJO 类。它包含四个属性eidenamesalarydeg。将这些属性视为表中的表字段,并将eid视为该表的主键。现在我们必须为此设计 hibernate 映射文件。名为mapping.xml的映射文件如下所示

<? xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm    
                        http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
                        version="1.0">
    <description> XML Mapping file</description>
    <entity class="Employee">        
        <table name="EMPLOYEETABLE"/>
        <attributes>
            <id name="eid">
                <generated-value strategy="TABLE"/>
            </id>
            <basic name="ename">
                <column name="EMP_NAME" length="100"/>
            </basic>
            <basic name="salary">
            </basic>
            <basic name="deg">
            </basic>
        </attributes>
    </entity>
</entity-mappings>

上述脚本用于将实体类与数据库表映射。在此文件中

  • <entity-mappings>:标记定义架构定义,以允许将实体标记添加到 xml 文件中。

  • <description>:标记提供有关应用程序的描述。

  • <entity>:标记定义要转换为数据库中表的实体类。class 属性定义 POJO 实体类名。

  • <table>:标记定义表名。如果希望类名和表名相同,则不需要此标记。

  • <attributes>:标记定义属性(表中的字段)。

  • <id>:标记定义表的主键。<generated-value>标记定义如何分配主键值,例如自动手动或从序列中获取。

  • <basic>:标记用于定义表的其余属性。

  • <column-name>:标记用于定义表中用户定义的表字段名。

注解

通常,xml 文件用于配置特定组件或映射两个不同规格的组件。在我们的例子中,我们必须在框架中分别维护 xml 文件。这意味着在编写映射 xml 文件时,我们需要将 POJO 类属性与 mapping.xml 文件中的实体标记进行比较。

这是一个解决方案。在类定义中,我们可以使用注解来编写配置部分。注解用于类、属性和方法。注解以“@”符号开头。注解声明在类、属性或方法之前。JPA 的所有注解都定义在javax.persistence包中。

以下是我们在示例中使用的注解列表。

注解 描述
@Entity 将类声明为实体或表。
@Table 声明表名。
@Basic 显式指定非约束字段。
@Embedded 指定其值为可嵌入类的实例的类或实体的属性。
@Id 指定属性,用于类的标识(表的主键)。
@GeneratedValue 指定标识属性的初始化方式,例如自动、手动或从序列表中获取值。
@Transient 指定非持久化属性,即值永远不会存储到数据库中。
@Column 指定持久化属性的列属性。
@SequenceGenerator 指定在 @GeneratedValue 注解中指定的属性的值。它创建一个序列。
@TableGenerator 指定在 @GeneratedValue 注解中指定的属性的值生成器。它创建一个用于值生成的表。
@AccessType 此类型的注解用于设置访问类型。如果设置 @AccessType(FIELD),则访问方式为字段级。如果设置 @AccessType(PROPERTY),则访问方式为属性级。
@JoinColumn 指定实体关联或实体集合。这用于多对一和一对多关联。
@UniqueConstraint 指定主键表或辅助表的字段和唯一约束。
@ColumnResult 使用 select 子句引用 SQL 查询中列的名称。
@ManyToMany 定义连接表之间的多对多关系。
@ManyToOne 定义连接表之间的多对一关系。
@OneToMany 定义连接表之间的一对多关系。
@OneToOne 定义连接表之间的一对一关系。
@NamedQueries 指定命名查询列表。
@NamedQuery 使用静态名称指定查询。

Java Bean 标准

Java 类将实例值及其行为封装到称为对象的单个单元中。Java Bean 是一个临时存储和可重用的组件或对象。它是一个可序列化的类,具有默认构造函数和 getter 和 setter 方法,用于分别初始化实例属性。

Bean 约定

  • Bean 包含其默认构造函数或包含序列化实例的文件。因此,一个 Bean 可以实例化另一个 Bean。

  • Bean 的属性可以分为布尔属性和非布尔属性。

  • 非布尔属性包含 **getter** 和 **setter** 方法。

  • 布尔属性包含 **setter** 和 **is** 方法。

  • 任何属性的 **getter** 方法都应以小写的 **get** 开头(Java 方法约定),然后继续使用以大写字母开头的字段名称。例如,字段名称为 **salary**,因此该字段的 getter 方法为 **getSalary ()**。

  • 任何属性的 **setter** 方法都应以小写的 **set** 开头(Java 方法约定),然后继续使用以大写字母开头的字段名称和要设置为字段的 **参数值**。例如,字段名称为 **salary**,因此该字段的 setter 方法为 **setSalary (double sal)**。

  • 对于布尔属性,**is** 方法用于检查其真假。例如,布尔属性 **empty**,该字段的 **is** 方法为 **isEmpty ()**。

JPA - 安装

本章将引导您完成在基于 Windows 和 Linux 的系统上设置 JPA 的过程。只需几个简单的步骤,即可轻松安装 JPA 并将其与您当前的 Java 环境集成,无需任何复杂的设置过程。安装过程中需要用户管理。

系统要求

JDK Java SE 2 JDK 1.5 或更高版本
内存 1 GB RAM(推荐)
磁盘空间 无最低要求
操作系统版本 Windows XP 或更高版本,Linux

现在让我们继续进行安装 JPA 的步骤。

步骤 1:验证您的 Java 安装

首先,您需要在系统上安装 Java 软件开发工具包 (SDK)。要验证这一点,请根据您正在使用的平台执行以下两个命令中的任何一个。

如果 Java 安装已正确完成,则它将显示您 Java 安装的当前版本和规范。示例输出如下表所示。

平台 命令 示例输出
Windows

打开命令控制台并输入

>java –version

Java version "1.7.0_60"

Java (TM) SE Run Time Environment (build 1.7.0_60-b19)

Java Hotspot (TM) 64-bit Server VM (build 24.60-b09, mixed mode)

Linux

打开命令终端并输入

$java –version

java version "1.7.0_25"

Open JDK Runtime Environment (rhel-2.3.10.4.el6_4-x86_64)

Open JDK 64-Bit Server VM (build 23.7-b01, mixed mode)

  • 我们假设本教程的读者在他们的系统上安装了 Java SDK 版本 1.7.0_60。

  • 如果您没有 Java SDK,请从此处下载其当前版本:[http://www.oracle.com/technetwork/java/javase/downloads/index.html](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 并安装它。

步骤 2:设置您的 Java 环境

设置环境变量 JAVA_HOME 以指向 Java 安装在您计算机上的基目录位置。例如:

平台 描述
Windows 将 JAVA_HOME 设置为 C:\ProgramFiles\java\jdk1.7.0_60
Linux export JAVA_HOME=/usr/local/java-current

将 Java 编译器位置的完整路径附加到系统路径。

平台 描述
Windows 将字符串“C:\Program Files\Java\jdk1.7.0_60\bin”附加到系统变量 PATH 的末尾。
Linux export PATH=$PATH:$JAVA_HOME/bin/

从命令提示符执行命令 **java -version**,如上所述。

步骤 3:安装 JPA

您可以通过使用本教程中的任何 JPA 提供程序来完成 JPA 安装,例如 EclipseLink、Hibernate。让我们按照使用 EclipseLink 安装 JPA 的方法进行操作。对于 JPA 编程,我们需要遵循特定的文件夹框架,因此最好使用 IDE。

从以下链接下载 Eclipse IDE:[https://www.eclipse.org/downloads/](https://www.eclipse.org/downloads/) 选择用于 Java EE 开发人员的 Eclipse IDE,即 **Eclipse indigo**。

将 Eclipse zip 文件解压缩到 C 盘。打开 Eclipse IDE。

Installing JPA

使用 EclipseLink 安装 JPA

EclipseLink 是一个库,因此我们无法将其直接添加到 Eclipse IDE 中。要使用 EclipseLink 安装 JPA,您需要按照以下步骤操作。

  • 通过在 Eclipse IDE 中选择 **文件 -> 新建 -> JPA 项目** 来创建一个新的 JPA 项目,如下所示

    New JPA
  • 您将获得一个名为 **新建 JPA 项目** 的对话框。输入项目名称 **tutorialspoint_JPA_Eclipselink**,检查 **jre** 版本并单击下一步

    Dialog Box
  • 在用户库部分单击下载库(如果您没有该库)。

    Download Library
  • 在下载库对话框中选择最新版本的 EclipseLink 库,然后单击下一步,如下所示

    Download Library Dialog Box
  • 接受许可证条款并单击完成以下载库。

    License
  • 6. 下载开始,如下图所示。

    Process
  • 下载完成后,在用户库部分选择下载的库,然后单击完成。

    Library Section
  • 最后,您将在 Eclipse IDE 的 **包资源管理器** 中获得项目文件。解压缩所有文件,您将获得如下所示的文件夹和文件层次结构

    Package Explorer

将 MySQL 连接器添加到项目

我们在此处讨论的任何示例都需要数据库连接。让我们考虑使用 MySQL 数据库进行数据库操作。它需要 mysql-connector jar 来与 Java 程序交互。

按照以下步骤在项目中配置数据库 jar。

  • 通过右键单击项目转到项目属性 **->** Java 构建路径。您将获得如下屏幕截图所示的对话框。单击添加外部 Jar。

    External Jars
  • 转到系统内存中的 jar 位置,选择文件并单击打开。

    Jar Location
  • 单击属性对话框上的确定。您将获得项目中的 MySQL-connector Jar。现在您可以使用 MySQL 进行数据库操作了。

JPA - 实体管理器

本章使用一个简单的示例来演示 JPA 的工作原理。让我们考虑员工管理为例。假设员工管理创建、更新、查找和删除员工记录。如前所述,我们使用 MySQL 数据库进行数据库操作。

此示例的主要模块如下所示

  • 模型或 POJO

    Employee.java

  • 持久性

    persistence.xml

  • 服务

    CreatingEmployee.java

    UpdatingEmployee.java

    FindingEmployee.java

    DeletingEmployee.java

让我们采用我们在使用 EclipseLink 进行 JPA 安装时使用的包层次结构。按照如下所示的层次结构进行此示例

Package Hierarchy

创建实体

实体不过是 Bean 或模型。在此示例中,我们将使用 **Employee** 作为实体。**eid**、**ename**、**salary** 和 **deg** 是此实体的属性。它包含一个默认构造函数以及这些属性的 setter 和 getter 方法。

在上图所示的层次结构中,在 **src**(源)包下创建一个名为 **'com.tutorialspoint.eclipselink.entity'** 的包。如下所示,在给定包下创建一个名为 **Employee.java** 的类

package com.tutorialspoint.eclipselink.entity;

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

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

在上面的代码中,我们使用了 @Entity 注解来使这个 POJO 类成为一个实体。

在进入下一个模块之前,我们需要为关系实体创建数据库,这将把数据库注册到 **persistence.xml** 文件中。打开 MySQL Workbench 并输入以下查询。

create database jpadb
use jpadb

persistence.xml

此模块在 JPA 的概念中起着至关重要的作用。在这个 xml 文件中,我们将注册数据库并指定实体类。

在上图所示的包层次结构中,JPA 内容包下的 persistence.xml 如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
                         	<class>com.tutorialspoint.eclipselink.entity.Employee</class>
	<properties>
	   <property name="javax.persistence.jdbc.url"
                   value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
     	   <property name="javax.persistence.jdbc.user" value="root"/>
	       <property name="javax.persistence.jdbc.password" value="root"/>
	       <property name="javax.persistence.jdbc.driver"
                   value="com.mysql.jdbc.Driver"/>
           <property name="eclipselink.logging.level" value="FINE"/>
	       <property name="eclipselink.ddl-generation" 
		           value="create-tables"/>
	</properties>
	</persistence-unit>
</persistence>

在上面的 xml 中,**<persistence-unit>** 标签用 JPA 持久性的特定名称定义。**<class>** 标签使用包名称定义实体类。**<properties>** 标签定义所有属性,**<property>** 标签定义每个属性,例如数据库注册、URL 指定、用户名和密码。这些是 EclipseLink 属性。此文件将配置数据库。

持久化操作

持久化操作用于与数据库交互,它们是 **加载** 和 **存储** 操作。在业务组件中,所有持久化操作都属于服务类。

在上图所示的包层次结构中,在 **src**(源)包下创建一个名为 **'com.tutorialspoint.eclipselink.service'** 的包。所有名为 CreateEmloyee.java、UpdateEmployee.java、FindEmployee.java 和 DeleteEmployee.java 的服务类都位于给定包下,如下所示

创建员工

以下代码段显示了如何创建一个名为 **CreateEmployee.java** 的 Employee 类。

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Employee;

public class CreateEmployee 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		Employee employee = new Employee( ); 
		employee.setEid( 1201 );
		employee.setEname( "Gopal" );
		employee.setSalary( 40000 );
		employee.setDeg( "Technical Manager" );
		entitymanager.persist( employee );
		entitymanager.getTransaction( ).commit( );
		
		entitymanager.close( );
		emfactory.close( );
	}
}

在上面的代码中,**createEntityManagerFactory ()** 通过提供与我们在 persistent.xml 文件中为 persistence-unit 提供的相同唯一名称来创建一个持久性单元。**entitymanagerfactory** 对象将使用 **createEntityManager ()** 方法创建 **entitymanger** 实例。**entitymanager** 对象为事务管理创建 **entitytransaction** 实例。通过使用 **entitymanager** 对象,我们可以将实体持久化到数据库中。

编译并执行上述程序后,您将在 Eclipse IDE 的控制面板上收到来自 EclipseLink 库的通知。

对于结果,打开 MySQL Workbench 并键入以下查询。

use jpadb
select * from employee

受影响的数据库表名为 **employee**,将以表格格式显示如下

Eid Ename Salary Deg
1201 Gopal 40000 技术经理

更新员工

要更新员工的记录,我们需要从数据库中检索现有记录,进行更改,最后将其提交到数据库。名为 **UpdateEmployee.java** 的类如下所示

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Employee;

public class UpdateEmployee 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
				entitymanager.getTransaction( ).begin( );
		Employee employee=entitymanager.
				find( Employee.class, 1201 );
		//before update
		System.out.println( employee );
		employee.setSalary( 46000 );
		entitymanager.getTransaction( ).commit( );
        //after update
		System.out.println( employee );
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制面板上收到来自 EclipseLink 库的通知。

对于结果,打开 MySQL Workbench 并键入以下查询。

use jpadb
select * from employee

受影响的数据库表名为 **employee**,将以表格格式显示如下

Eid Ename Salary Deg
1201 Gopal 46000 技术经理

员工 1201 的薪水已更新为 46000。

查找员工

要查找员工的记录,我们将不得不从数据库中检索现有数据并将其显示出来。在此操作中,在检索记录时不应用 EntityTransaction。

名为 **FindEmployee.java** 的类如下所示。

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Employee;

public class FindEmployee 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence
				.createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager();
		Employee employee = entitymanager.
				find( Employee.class, 1201 );
		
		System.out.println("employee ID = "+employee.getEid( ));
		System.out.println("employee NAME = "+employee.getEname( ));
		System.out.println("employee SALARY = "+employee.getSalary( ));
		System.out.println("employee DESIGNATION = "+employee.getDeg( ));
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制面板上收到来自 EclipseLink 库的以下输出。

employee ID = 1201
employee NAME = Gopal
employee SALARY = 46000.0
employee DESIGNATION = Technical Manager

删除员工

要删除员工的记录,我们首先将查找现有记录,然后将其删除。这里 EntityTransaction 起着重要的作用。

名为 **DeleteEmployee.java** 的类如下所示

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Employee;

public class DeleteEmployee 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		Employee employee=entitymanager.
				find( Employee.class, 1201 );
		entitymanager.remove( employee );
		entitymanager.getTransaction( ).commit( );
		entitymanager.close( );
		emfactory.close( );
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制面板上收到来自 EclipseLink 库的通知。

对于结果,打开 MySQL Workbench 并键入以下查询。

use jpadb
select * from employee

受影响的数据库名为 **employee** 将包含空记录。

完成本示例中所有模块后,包和文件层次结构如下所示

Modules

JPA - JPQL

本章介绍 JPQL 及其与持久化单元的协同工作方式。本章中给出的示例遵循与上一章相同的包层次结构。

JPA JPQL

Java 持久化查询语言

JPQL 代表 Java 持久化查询语言 (Java Persistence Query Language)。它用于创建针对实体的查询,以将数据存储到关系数据库中。JPQL 基于 SQL 语法开发。但它不会直接影响数据库。

JPQL 可以使用 SELECT 语句检索数据,可以使用 UPDATE 语句和 DELETE 语句进行批量更新。

查询结构

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 技术经理
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 中相同,但它处理的是实体。以下示例演示如何使用 ORDER BY 子句。

创建一个名为 **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 注解添加到位于 **com.tutorialspoint.eclipselink.entity** 包下的名为 **Employee.java** 的 Employee 实体类中,内容如下所示。

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 最重要的概念是在缓存内存中创建数据库的副本。在与数据库进行事务处理时,JPA 首先创建一组重复的数据,只有当使用实体管理器提交时,更改才会影响到数据库。

有两种从数据库中提取记录的方法。

急切加载

在急切加载中,在提取特定记录时会自动上传相关的子对象。

延迟加载

在延迟加载中,除非您专门请求,否则不会自动上传相关对象。首先,它检查相关对象的可访问性并发出通知。稍后,如果您调用该实体的任何 getter 方法,它将提取所有记录。

当您第一次尝试提取记录时,延迟加载是可能的。这样,整个记录的副本已经存储在缓存内存中。从性能方面来看,延迟加载更可取。

JPA - 高级映射

JPA 是一个随 Java 规范发布的库。因此,它支持所有面向对象的实体持久化概念。到目前为止,我们已经完成了对象关系映射的基础知识。本章将带您了解对象和关系实体之间的高级映射。

继承策略

继承是任何面向对象语言的核心概念,因此我们可以在实体之间使用继承关系或策略。JPA 支持三种类型的继承策略:SINGLE_TABLE、JOINED_TABLE 和 TABLE_PER_CONCRETE_CLASS。

让我们考虑一个示例。下图显示了三个类,即 Staff、TeachingStaff 和 NonTeachingStaff,以及它们之间的关系。

Inheritance Strategy

在上图中,Staff 是一个实体,而 TeachingStaff 和 NonTeachingStaff 是 Staff 的子实体。我们将使用上述示例来演示所有三种继承策略。

单表策略

单表策略采用所有类的字段(超类和子类)并将它们映射到一个名为 SINGLE_TABLE 的单表中。在此,鉴别器值在区分单表中三个实体的值方面起着关键作用。

让我们考虑上述示例。TeachingStaff 和 NonTeachingStaff 是 Staff 的子类。根据继承的概念,子类继承其超类的属性。因此,sid 和 sname 是属于 TeachingStaff 和 NonTeachingStaff 的字段。创建一个 JPA 项目。该项目的所有模块如下所示

创建实体

在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.entity’** 的包。在给定包下创建一个名为 **Staff.java** 的新 Java 类。Staff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import java.io.Serializable;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name="type" )
public class Staff implements Serializable 
{
	@Id
	@GeneratedValue( strategy = GenerationType.AUTO )
	private int sid;
	private String sname;
	public Staff( int sid, String sname ) 
	{
		super( );
		this.sid = sid;
		this.sname = sname;
	}
	public Staff( ) 
	{
		super( );
	}
	public int getSid( ) 
	{
		return sid;
	}
	public void setSid( int sid ) 
	{
		this.sid = sid;
	}
	public String getSname( ) 
	{
		return sname;
	}
	public void setSname( String sname ) 
	{
		this.sname = sname;
	}
}

在上面的代码中,**@DescriminatorColumn** 指定字段名称 **(type)**,其值显示其余 (Teaching 和 NonTeachingStaff) 字段。

为 Staff 类创建一个子类 (class),名为 **TeachingStaff.java**,放在 **com.tutorialspoint.eclipselink.entity** 包下。TeachingStaff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue( value="TS" )
public class TeachingStaff extends Staff 
{
	private String qualification;
	private String subjectexpertise;
	
	public TeachingStaff( int sid, String sname, 
			String qualification,String subjectexpertise ) 
	{
		super( sid, sname );
		this.qualification = qualification;
		this.subjectexpertise = subjectexpertise;
	}
	
	public TeachingStaff( ) 
	{
		super( );
	}

	public String getQualification( )
	{
		return qualification;
	}

	public void setQualification( String qualification )
	{
		this.qualification = qualification;
	}

	public String getSubjectexpertise( ) 
	{
		return subjectexpertise;
	}

	public void setSubjectexpertise( String subjectexpertise )
	{
		this.subjectexpertise = subjectexpertise;
	}
}

为 Staff 类创建一个子类 (class),名为 **NonTeachingStaff.java**,放在 **com.tutorialspoint.eclipselink.entity** 包下。NonTeachingStaff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue( value = "NS" )
public class NonTeachingStaff extends Staff 
{
	private String areaexpertise;

	public NonTeachingStaff( int sid, String sname, 
			String areaexpertise ) 
	{
		super( sid, sname );
		this.areaexpertise = areaexpertise;
	}

	public NonTeachingStaff( ) 
	{
		super( );
	}

	public String getAreaexpertise( ) 
	{
		return areaexpertise;
	}

	public void setAreaexpertise( String areaexpertise )
	{
		this.areaexpertise = areaexpertise;
	}
}

persistence.xml

persistence.xml 包含数据库的配置信息和实体类的注册信息。xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	    <class>com.tutorialspoint.eclipselink.entity.Staff</class>
		<class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
		<class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
                            value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
                            value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
                            value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

服务类是业务组件的实现部分。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。

在给定包下创建一个名为 **SaveClient.java** 的类,以存储 Staff、TeachingStaff 和 NonTeachingStaff 类字段。SaveClient 类如下所示

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;

public class SaveClient 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Teaching staff entity 
		TeachingStaff ts1=new TeachingStaff(
				1,"Gopal","MSc MEd","Maths");
		TeachingStaff ts2=new TeachingStaff(
				2, "Manisha", "BSc BEd", "English");
		//Non-Teaching Staff entity
		NonTeachingStaff nts1=new NonTeachingStaff(
				3, "Satish", "Accounts");
		NonTeachingStaff nts2=new NonTeachingStaff(
				4, "Krishna", "Office Admin");
		
		//storing all entities
		entitymanager.persist(ts1);
		entitymanager.persist(ts2);
		entitymanager.persist(nts1);
		entitymanager.persist(nts2);
		entitymanager.getTransaction().commit();
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上收到通知。检查 MySQL 工作台以查看输出。表格格式的输出如下所示

Sid Type Sname Areaexpertise Qualification Subjectexpertise
1 TS Gopal MSC MED Maths
2 TS Manisha BSC BED English
3 NS Satish Accounts
4 NS Krishna Office Admin

最终,您将获得一个包含所有三个类的字段以及名为 **Type** (字段) 的鉴别器列的单表。

连接表策略

连接表策略是共享包含唯一值的引用列以连接表并简化事务。让我们考虑与上面相同的示例。

创建一个 JPA 项目。所有项目模块如下所示。

创建实体

在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.entity’** 的包。在给定包下创建一个名为 **Staff.java** 的新 Java 类。Staff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table
@Inheritance( strategy = InheritanceType.JOINED )
public class Staff implements Serializable 
{
	@Id
	@GeneratedValue( strategy = GenerationType.AUTO )
	private int sid;
	private String sname;
	public Staff( int sid, String sname ) 
	{
		super( );
		this.sid = sid;
		this.sname = sname;
	}
	public Staff( ) 
	{
		super( );
	}
	public int getSid( ) 
	{
		return sid;
	}
	public void setSid( int sid ) 
	{
		this.sid = sid;
	}
	public String getSname( ) 
	{
		return sname;
	}
	public void setSname( String sname ) 
	{
		this.sname = sname;
	}
}

为 Staff 类创建一个子类 (class),名为 **TeachingStaff.java**,放在 **com.tutorialspoint.eclipselink.entity** 包下。TeachingStaff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@PrimaryKeyJoinColumn(referencedColumnName="sid")
public class TeachingStaff extends Staff 
{
	private String qualification;
	private String subjectexpertise;
	
	public TeachingStaff( int sid, String sname, 
			String qualification,String subjectexpertise ) 
	{
		super( sid, sname );
		this.qualification = qualification;
		this.subjectexpertise = subjectexpertise;
	}
	
	public TeachingStaff( ) 
	{
		super( );
		
	}

	public String getQualification( )
	{
		return qualification;
	}

	public void setQualification( String qualification )
	{
		this.qualification = qualification;
	}

	public String getSubjectexpertise( ) 
	{
		return subjectexpertise;
	}

	public void setSubjectexpertise( String subjectexpertise )
	{
		this.subjectexpertise = subjectexpertise;
	}
}

为 Staff 类创建一个子类 (class),名为 **NonTeachingStaff.java**,放在 **com.tutorialspoint.eclipselink.entity** 包下。NonTeachingStaff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@PrimaryKeyJoinColumn(referencedColumnName="sid")
public class NonTeachingStaff extends Staff 
{
	private String areaexpertise;

	public NonTeachingStaff( int sid, String sname, 
			String areaexpertise ) 
	{
		super( sid, sname );
		this.areaexpertise = areaexpertise;
	}

	public NonTeachingStaff( ) 
	{
		super( );
	}

	public String getAreaexpertise( ) 
	{
		return areaexpertise;
	}

	public void setAreaexpertise( String areaexpertise )
	{
		this.areaexpertise = areaexpertise;
	}
}

persistence.xml

persistence.xml 文件包含数据库的配置信息和实体类的注册信息。xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Staff</class>
	<class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
	<class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
                            value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
                            value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
                            value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

服务类是业务组件的实现部分。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。

在给定包下创建一个名为 **SaveClient.java** 的类,以存储 Staff、TeachingStaff 和 NonTeachingStaff 类字段。然后,SaveClient 类如下所示

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;

public class SaveClient 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Teaching staff entity 
		TeachingStaff ts1=new TeachingStaff(
				1,"Gopal","MSc MEd","Maths");
		TeachingStaff ts2=new TeachingStaff(
				2, "Manisha", "BSc BEd", "English");
		//Non-Teaching Staff entity
		NonTeachingStaff nts1=new NonTeachingStaff(
				3, "Satish", "Accounts");
		NonTeachingStaff nts2=new NonTeachingStaff(
		4, "Krishna", "Office Admin");
		
		//storing all entities
		entitymanager.persist(ts1);
		entitymanager.persist(ts2);
		entitymanager.persist(nts1);
		entitymanager.persist(nts2);
		
		entitymanager.getTransaction().commit();
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上收到通知。有关输出,请检查 MySQL 工作台。

这里创建了三个表,并在表格格式中显示了 **staff** 表的结果。

Sid Dtype Sname
1 TeachingStaff Gopal
2 TeachingStaff Manisha
3 NonTeachingStaff Satish
4 NonTeachingStaff Krishna

**TeachingStaff** 表的结果如下所示

Sid Qualification Subjectexpertise
1 MSC MED Maths
2 BSC BED English

在上表中,sid 是外键(来自 staff 表的引用字段)。**NonTeachingStaff** 表的结果如下所示

Sid Areaexpertise
3 Accounts
4 Office Admin

最后,使用各自的字段创建三个表,并且 SID 字段由所有三个表共享。在 Staff 表中,SID 是主键。在其余两个表(TeachingStaff 和 NonTeachingStaff)中,SID 是外键。

每个类一个表策略

每个类一个表策略是为每个子实体创建一个表。将创建 Staff 表,但它将包含空值。Staff 表的字段值必须由 TeachingStaff 和 NonTeachingStaff 表共享。

让我们考虑与上面相同的示例。

创建实体

在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.entity’** 的包。在给定包下创建一个名为 **Staff.java** 的新 Java 类。Staff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

@Entity
@Table
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS )
public class Staff implements Serializable 
{
	@Id
	@GeneratedValue( strategy = GenerationType.AUTO )
	private int sid;
	private String sname;
	public Staff( int sid, String sname ) 
	{
		super( );
		this.sid = sid;
		this.sname = sname;
	}
	public Staff( ) 
	{
		super( );
	}
	public int getSid( ) 
	{
		return sid;
	}
	public void setSid( int sid ) 
	{
		this.sid = sid;
	}
	public String getSname( ) 
	{
		return sname;
	}
	public void setSname( String sname ) 
	{
		this.sname = sname;
	}
}

为 Staff 类创建一个子类 (class),名为 **TeachingStaff.java**,放在 **com.tutorialspoint.eclipselink.entity** 包下。TeachingStaff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
public class TeachingStaff extends Staff 
{
	private String qualification;
	private String subjectexpertise;
	
	public TeachingStaff( int sid, String sname, 
			String qualification,String subjectexpertise ) 
	{
		super( sid, sname );
		this.qualification = qualification;
		this.subjectexpertise = subjectexpertise;
	}
	
	public TeachingStaff( ) 
	{
		super( );
		
	}

	public String getQualification( )
	{
		return qualification;
	}
	public void setQualification( String qualification )
	{
		this.qualification = qualification;
	}

	public String getSubjectexpertise( ) 
	{
		return subjectexpertise;
	}

	public void setSubjectexpertise( String subjectexpertise )
	{
		this.subjectexpertise = subjectexpertise;
	}
}

为 Staff 类创建一个子类 (class),名为 **NonTeachingStaff.java**,放在 **com.tutorialspoint.eclipselink.entity** 包下。NonTeachingStaff 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
public class NonTeachingStaff extends Staff 
{
	private String areaexpertise;

	public NonTeachingStaff( int sid, String sname, 
			String areaexpertise )
			{
		super( sid, sname );
		this.areaexpertise = areaexpertise;
	}

	public NonTeachingStaff( ) 
	{
		super( );
	}

	public String getAreaexpertise( ) 
	{
		return areaexpertise;
	}

	public void setAreaexpertise( String areaexpertise )
	{
		this.areaexpertise = areaexpertise;
	}
}

persistence.xml

persistence.xml 文件包含数据库的配置信息和实体类的注册信息。xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Staff</class>
	<class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
	<class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
                            value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
                            value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
                            value="create-tables"/>
			</properties>
	</persistence-unit>
</persistence>

服务类

服务类是业务组件的实现部分。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。

在给定包下创建一个名为 **SaveClient.java** 的类,以存储 Staff、TeachingStaff 和 NonTeachingStaff 类字段。SaveClient 类如下所示

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;
public class SaveClient 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Teaching staff entity 
		TeachingStaff ts1=new TeachingStaff(
				1,"Gopal","MSc MEd","Maths");
		TeachingStaff ts2=new TeachingStaff(
				2, "Manisha", "BSc BEd", "English");
		//Non-Teaching Staff entity
		NonTeachingStaff nts1=new NonTeachingStaff(
				3, "Satish", "Accounts");
		NonTeachingStaff nts2=new NonTeachingStaff(
				4, "Krishna", "Office Admin");
		
		//storing all entities
		entitymanager.persist(ts1);
		entitymanager.persist(ts2);
		entitymanager.persist(nts1);
		entitymanager.persist(nts2);
		
		entitymanager.getTransaction().commit();
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上收到通知。有关输出,请检查 MySQL 工作台。

这里创建了三个表,并且 **Staff** 表包含空记录。

**TeachingStaff** 的结果如下所示

Sid Qualification Sname Subjectexpertise
1 MSC MED Gopal Maths
2 BSC BED Manisha English

上表 TeachingStaff 包含 Staff 和 TeachingStaff 实体的字段。

**NonTeachingStaff** 的结果如下所示

Sid Areaexpertise Sname
3 Accounts Satish
4 Office Admin Krishna

上表 NonTeachingStaff 包含 Staff 和 NonTeachingStaff 实体的字段。

JPA - 实体关系

本章将带您了解实体之间的关系。通常,关系在数据库中的表之间更有效。这里实体类被视为关系表(JPA 的概念),因此实体类之间的关系如下所示

  • @ManyToOne 关系
  • @OneToMany 关系
  • 一对一关系
  • 多对多关系

@ManyToOne 关系

实体之间存在多对一关系,其中一个实体(列或列集)被另一个包含唯一值的实体(列或列集)引用。在关系数据库中,这些关系是通过使用表之间的外键/主键来实现的。

让我们考虑一下员工和部门实体之间关系的示例。以单向方式,即从员工到部门,适用多对一关系。这意味着每个员工记录都包含一个部门 ID,该 ID 应该是部门表中的主键。此处,在员工表中,部门 ID 是外键。

下图显示了这两个表之间的多对一关系。

@ManyToOne Relation

在 Eclipse IDE 中创建一个名为 **JPA_Eclipselink_MTO** 的 JPA 项目。下面将讨论该项目的所有模块。

创建实体

按照上面给出的图表创建实体。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoin.eclipselink.entity’** 的包。在给定的包下创建一个名为 **Department.java** 的类。Department 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

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

@Entity
public class Department 
{
    @Id 
    @GeneratedValue( strategy=GenerationType.AUTO )
    private int id;
    private String name;

    public int getId() 
    {
    	return id;
    }
    
    public void setId(int id) 
    {
    	this.id = id;
    }
    
    public String getName( )
    {
    	return name;
    }
    
    public void setName( String deptName )
    {
    	this.name = deptName;
    }
}

在此关系中创建第二个实体 - Employee 实体类,名为 **Employee.java**,位于 **‘com.tutorialspoint.eclipselink.entity’** 包下。Employee 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Employee 
{
	@Id
	@GeneratedValue( strategy= GenerationType.AUTO ) 	
	private int eid;
	private String ename;
	private double salary;
	private String deg;
	@ManyToOne
	private Department department;
	
	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;
	}
		
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}
}

persistence.xml

需要 persistence.xml 文件来配置数据库和实体类的注册。

创建 JPA 项目时,Eclipse IDE 将创建 Persitence.xml 文件。配置详细信息是用户指定的。persistence.xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 
             xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Employee</class>
	<class>com.tutorialspoint.eclipselink.entity.Department</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
			          value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password"
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
			          value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
			          value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

此模块包含服务类,这些类使用属性初始化来实现关系部分。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。在给定的包下创建名为 **ManyToOne.java** 的 DAO 类。DAO 类如下所示

package com.tutorialspointeclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Department;
import com.tutorialspoint.eclipselink.entity.Employee;

public class ManyToOne 
{
	public static void main( String[ ] args ) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Create Department Entity
		Department department = new Department();
		department.setName("Development");
		//Store Department
		entitymanager.persist(department);
		
		//Create Employee1 Entity
		Employee employee1 = new Employee();
		employee1.setEname("Satish");
		employee1.setSalary(45000.0);
		employee1.setDeg("Technical Writer");
		employee1.setDepartment(department);

		//Create Employee2 Entity
		Employee employee2 = new Employee();
		employee2.setEname("Krishna");
		employee2.setSalary(45000.0);
		employee2.setDeg("Technical Writer");
		employee2.setDepartment(department);

		//Create Employee3 Entity
		Employee employee3 = new Employee();
		employee3.setEname("Masthanvali");
		employee3.setSalary(50000.0);
		employee3.setDeg("Technical Writer");
		employee3.setDepartment(department);
		
		//Store Employees
		entitymanager.persist(employee1);
		entitymanager.persist(employee2);
		entitymanager.persist(employee3);
				
		entitymanager.getTransaction().commit();
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上收到通知。有关输出,请检查 MySQL workbench。在此示例中,将创建两个表。

在 MySQL 接口中传递以下查询,并将显示 **Department** 表的结果,如下所示

Select * from department
ID 名称
101 开发部

在 MySQL 接口中传递以下查询,并将显示 **Employee** 表的结果,如下所示。

Select * from employee
Eid Deg Ename Salary Department_Id
102 技术撰稿人 Satish 45000 101
103 技术撰稿人 Krishna 45000 101
104 技术撰稿人 Masthanwali 50000 101

在上表中,Deparment_Id 是来自 Department 表的外键(引用字段)。

@OneToMany 关系

在此关系中,一个实体的每一行都引用另一个实体中的许多子记录。重要的是,子记录不能有多个父记录。在一个表 A 和表 B 之间的一对多关系中,表 A 中的每一行都可以链接到表 B 中的一行或多行。

让我们考虑上面的示例。假设上面示例中的 Employee 和 Department 表以相反的单向方式连接,则关系变为一对多关系。在 Eclipse IDE 中创建一个名为 **JPA_Eclipselink_OTM** 的 JPA 项目。下面将讨论该项目的所有模块。

创建实体

按照上面给出的图表创建实体。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoin.eclipselink.entity’** 的包。在给定的包下创建一个名为 **Department.java** 的类。Department 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Department 
{
    @Id 
    @GeneratedValue( strategy=GenerationType.AUTO )
    private int id;
    private String name;
    
    @OneToMany( targetEntity=Employee.class )
    private List employeelist;

    public int getId() 
    {
    	return id;
    }
    
    public void setId(int id) 
    {
    	this.id = id;
    }
    
    public String getName( )
    {
    	return name;
    }
    
    public void setName( String deptName )
    {
    	this.name = deptName;
    }

    public List getEmployeelist() 
    {
	return employeelist;
    }

    public void setEmployeelist(List employeelist) 
    {
	this.employeelist = employeelist;
    }
}

在此关系中创建第二个实体 - Employee 实体类,名为 **Employee.java**,位于 **‘com.tutorialspoint.eclipselink.entity’** 包下。Employee 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

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

@Entity
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;
	}	
}

persistence.xml

persistence.xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 
             xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Employee</class>
	<class>com.tutorialspoint.eclipselink.entity.Department</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
			          value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
			          value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
			          value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

此模块包含服务类,这些类使用属性初始化来实现关系部分。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。在给定的包下创建名为 **OneToMany.java** 的 DAO 类。DAO 类如下所示

package com.tutorialspointeclipselink.service;

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

public class OneToMany 
{
	public static void main(String[] args) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Create Employee1 Entity
		Employee employee1 = new Employee();
		employee1.setEname("Satish");
		employee1.setSalary(45000.0);
		employee1.setDeg("Technical Writer");
								
		//Create Employee2 Entity
		Employee employee2 = new Employee();
		employee2.setEname("Krishna");
		employee2.setSalary(45000.0);
		employee2.setDeg("Technical Writer");
								
		//Create Employee3 Entity
		Employee employee3 = new Employee();
		employee3.setEname("Masthanvali");
		employee3.setSalary(50000.0);
		employee3.setDeg("Technical Writer");
		
		//Store Employee
		entitymanager.persist(employee1);
		entitymanager.persist(employee2);
		entitymanager.persist(employee3);
		
		//Create Employeelist
		List<Employee> emplist = new ArrayList();
		emplist.add(employee1);
		emplist.add(employee2);
		emplist.add(employee3);
		
		//Create Department Entity
		Department department= new Department();
		department.setName("Development");
		department.setEmployeelist(emplist);
				
		//Store Department
		entitymanager.persist(department);
		
		entitymanager.getTransaction().commit();
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上收到通知。有关输出,请检查 MySQL workbench,如下所示。

在此项目中创建了三个表。在 MySQL 接口中传递以下查询,并将显示 department_employee 表的结果,如下所示

Select * from department_Id;
Department_ID Employee_Eid
254 251
254 252
254 253

在上表中,**deparment_id** 和 **employee_id** 是来自 department 和 employee 表的外键(引用字段)。

在 MySQL 接口中传递以下查询,并将以表格格式显示 department 表的结果,如下所示。

Select * from department;
ID 名称
254 开发部

在 MySQL 接口中传递以下查询,并将显示 employee 表的结果,如下所示

Select * from employee;
Eid Deg Ename Salary
251 技术撰稿人 Satish 45000
252 技术撰稿人 Krishna 45000
253 技术撰稿人 Masthanwali 50000

一对一关系

在一对一关系中,一个项目只能链接到另一个项目。这意味着一个实体的每一行都只引用另一个实体的一行。

让我们考虑上面的示例。**Employee** 和 **Department** 以相反的单向方式,关系是一对一关系。这意味着每个员工只属于一个部门。在 Eclipse IDE 中创建一个名为 **JPA_Eclipselink_OTO** 的 JPA 项目。下面将讨论该项目的所有模块。

创建实体

按照上面给出的图表创建实体。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoin.eclipselink.entity’** 的包。在给定的包下创建一个名为 **Department.java** 的类。Department 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

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

@Entity
public class Department 
{
    @Id 
    @GeneratedValue( strategy=GenerationType.AUTO )
    private int id;
    private String name;
   
    public int getId() 
    {
    	return id;
    }
    
    public void setId(int id) 
    {
    	this.id = id;
    }
    
    public String getName( )
    {
    	return name;
    }
    
    public void setName( String deptName )
    {
    	this.name = deptName;
    }
}

在此关系中创建第二个实体 - Employee 实体类,名为 **Employee.java**,位于 **‘com.tutorialspoint.eclipselink.entity’** 包下。Employee 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Employee 
{
	@Id
	@GeneratedValue( strategy= GenerationType.AUTO ) 	
	private int eid;
	private String ename;
	private double salary;
	private String deg;
	
	@OneToOne
	private Department department;
		
	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;
	}

	public Department getDepartment() 
	{
		return department;
	}

	public void setDepartment(Department department) 
	{
		this.department = department;
	}	
}

persistence.xml

persistence.xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 
             xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Employee</class>
	<class>com.tutorialspoint.eclipselink.entity.Department</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
			          value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
			          value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
			          value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。在给定的包下创建名为 **OneToOne.java** 的 DAO 类。DAO 类如下所示

package com.tutorialspointeclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Department;
import com.tutorialspoint.eclipselink.entity.Employee;

public class OneToOne 
{
	public static void main(String[] args) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Create Department Entity
		Department department = new Department();
		department.setName("Development");
		
		//Store Department
		entitymanager.persist(department);
		
		//Create Employee Entity
		Employee employee = new Employee();
		employee.setEname("Satish");
		employee.setSalary(45000.0);
		employee.setDeg("Technical Writer");
		employee.setDepartment(department);
		
		//Store Employee
		entitymanager.persist(employee);
		
		entitymanager.getTransaction().commit();
		entitymanager.close();
		emfactory.close();
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上收到通知。有关输出,请检查 MySQL workbench,如下所示。

在上面的示例中,创建了两个表。在 MySQL 接口中传递以下查询,并将显示 department 表的结果,如下所示

Select * from department
ID 名称
301 开发部

在 MySQL 接口中传递以下查询,并将显示 **employee** 表的结果,如下所示

Select * from employee
Eid Deg Ename Salary Department_id
302 技术撰稿人 Satish 45000 301

多对多关系

多对多关系是指一个实体的一行或多行与另一个实体的多行关联。

让我们考虑一下两个实体之间关系的示例:**班级**和**老师**。以双向方式,班级和老师都具有多对一关系。这意味着每个班级的记录都被老师集(教师 ID)引用,这些 ID 应该是教师表中的主键,并存储在 Teacher_Class 表中,反之亦然。这里,Teachers_Class 表包含两个外键字段。在 Eclipse IDE 中创建一个名为 **JPA_Eclipselink_MTM** 的 JPA 项目。下面将讨论该项目的所有模块。

@ManyToOne Relation

创建实体

按照上面图表中显示的模式创建实体。在 **‘src’** 包下创建一个名为 **‘com.tutorialspoin.eclipselink.entity’** 的包。在给定的包下创建一个名为 **Clas.java** 的类。Department 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Clas 
{
	@Id
	@GeneratedValue( strategy = GenerationType.AUTO )
	private int cid;
	private String cname;
	
	@ManyToMany(targetEntity=Teacher.class)
	private Set teacherSet;
	
	public Clas() 
	{
		super();
	}
	public Clas(int cid, 
			String cname, Set teacherSet) 
	{
		super();
		this.cid = cid;
		this.cname = cname;
		this.teacherSet = teacherSet;
	}
	public int getCid() 
	{
		return cid;
	}
	public void setCid(int cid) 
	{
		this.cid = cid;
	}
	public String getCname() 
	{
		return cname;
	}
	public void setCname(String cname) 
	{
		this.cname = cname;
	}
	public Set getTeacherSet() 
	{
		return teacherSet;
	}
	public void setTeacherSet(Set teacherSet) 
	{
		this.teacherSet = teacherSet;
	}	  
}

在此关系中创建第二个实体 - Employee 实体类,名为 **Teacher.java**,位于 **‘com.tutorialspoint.eclipselink.entity’** 包下。Employee 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Teacher 
{
	@Id
	@GeneratedValue( strategy = GenerationType.AUTO )
	private int tid;
	private String tname;
	private String subject;
	
	@ManyToMany(targetEntity=Clas.class)
	private Set clasSet;
	
	public Teacher() 
	{
		super();
	}
	public Teacher(int tid, String tname, String subject, 
			Set clasSet) 
	{
		super();
		this.tid = tid;
		this.tname = tname;
		this.subject = subject;
		this.clasSet = clasSet;
	}
	public int getTid() 
	{
		return tid;
	}
	public void setTid(int tid) 
	{
		this.tid = tid;
	}
	public String getTname() 
	{
		return tname;
	}
	public void setTname(String tname) 
	{
		this.tname = tname;
	}
	public String getSubject() 
	{
		return subject;
	}
	public void setSubject(String subject) 
	{
		this.subject = subject;
	}
	public Set getClasSet() 
	{
		return clasSet;
	}
	public void setClasSet(Set clasSet) 
	{
		this.clasSet = clasSet;
	}
}

persistence.xml

persistence.xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 
             xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Employee</class>
	<class>com.tutorialspoint.eclipselink.entity.Department</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
			          value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
                            value="root"/>
			<property name="javax.persistence.jdbc.driver" 
			          value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
			          value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

在 **‘src’** 包下创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。在给定的包下创建名为 **ManyToMany.java** 的 DAO 类。DAO 类如下所示

package com.tutorialspoint.eclipselink.service;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.Clas;
import com.tutorialspoint.eclipselink.entity.Teacher;

public class ManyToMany 
{
	public static void main(String[] args) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		entitymanager.getTransaction( ).begin( );
		
		//Create Clas Entity
		Clas clas1=new Clas(0,"1st",null);
		Clas clas2=new Clas(0,"2nd",null);
		Clas clas3=new Clas(0,"3rd",null);
		
		//Store Clas
		entitymanager.persist(clas1);
		entitymanager.persist(clas2);
		entitymanager.persist(clas3);
		
		//Create Clas Set1
		Set<Clas> classSet1 = new HashSet();
		classSet1.add(clas1);
		classSet1.add(clas2);
		classSet1.add(clas3);
		
		//Create Clas Set2
		Set<Clas> classSet2 = new HashSet();
		classSet2.add(clas3);
		classSet2.add(clas1);
		classSet2.add(clas2);
				
		//Create Clas Set3
		Set<Clas> classSet3 = new HashSet();
		classSet3.add(clas2);
		classSet3.add(clas3);
		classSet3.add(clas1);
		
		//Create Teacher Entity
		Teacher teacher1 = new Teacher(0,
				"Satish","Java",classSet1);
		Teacher teacher2 = new Teacher(0,
				"Krishna","Adv Java",classSet2);
		Teacher teacher3 = new Teacher(0,
				"Masthanvali","DB2",classSet3);
		
		//Store Teacher
		entitymanager.persist(teacher1);
		entitymanager.persist(teacher2);
		entitymanager.persist(teacher3);
		
		entitymanager.getTransaction( ).commit( );
		entitymanager.close( );
		emfactory.close( );
	}
}

在此示例项目中,创建了三个表。在 MySQL 接口中传递以下查询,并将显示 teacher_clas 表的结果,如下所示

Select * form teacher_clas
Teacher_tid Classet_cid
354 351
355 351
356 351
354 352
355 352
356 352
354 353
355 353
356 353

在上表中,**teacher_tid** 是来自 teacher 表的外键,**classet_cid** 是来自 class 表的外键。因此,不同的老师被分配到不同的班级。

在 MySQL 接口中传递以下查询,并将显示 teacher 表的结果,如下所示

Select * from teacher
Tid 科目 姓名
354 Java Satish
355 高级Java Krishna
356 DB2 Masthanvali

在 MySQL 接口中传递以下查询,并将显示 **clas** 表的结果,如下所示

Select * from clas
Cid 班级名称
351 一年级
352 二年级
353 三年级

JPA - Criteria API

Criteria 是一个预定义的 API,用于定义实体的查询。它是定义 JPQL 查询的替代方法。这些查询是类型安全的、可移植的,并且易于通过更改语法来修改。与 JPQL 类似,它遵循抽象模式(易于编辑的模式)和嵌入式对象。元数据 API 与 Criteria API 混合在一起,用于为 Criteria 查询建模持久实体。

Criteria API 的主要优点是可以在编译时更早地检测到错误。基于字符串的 JPQL 查询和基于 JPA Criteria 的查询在性能和效率上相同。

Criteria API 的历史

Criteria 包含在所有版本的 JPA 中,因此 JPA 规范中会通知 Criteria 的每个步骤。

  • 在 JPA 2.0 中,开发了 Criteria 查询 API,对查询进行了标准化。
  • 在 JPA 2.1 中,包含了 Criteria 更新和删除(批量更新和删除)。

Criteria 查询结构

Criteria 和 JPQL 密切相关,并允许在其查询中使用类似的操作符进行设计。它遵循 **javax.persistence.criteria** 包来设计查询。查询结构表示语法 Criteria 查询。

以下简单的 Criteria 查询返回数据源中实体类的所有实例。

EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Entity class> cq = cb.createQuery(Entity.class);
Root<Entity> from = cq.from(Entity.class);
cq.select(Entity);
TypedQuery<Entity> q = em.createQuery(cq);
List<Entity> allitems = q.getResultList();

该查询演示了创建 Criteria 的基本步骤。

  • 使用 **EntityManager** 实例创建 CriteriaBuilder 对象。

  • 使用 **CriteriaQuery** 实例创建查询对象。此查询对象的属性将使用查询的详细信息进行修改。

  • 调用 **CriteriaQuery.form** 方法来设置查询根。

  • 调用 **CriteriaQuery.select** 来设置结果列表类型。

  • 使用 **TypedQuery<T>** 实例准备要执行的查询并指定查询结果的类型。

  • 在 TypedQuery<T> 对象上使用 **getResultList** 方法执行查询。此查询返回实体集合,结果存储在列表中。

Criteria API 示例

让我们考虑一下员工数据库的示例。让我们假设 jpadb.employee 表包含以下记录

Eid	 Ename          Salary	Deg
401	 Gopal	        40000	Technical Manager
402	 Manisha	    40000	Proof reader
403	 Masthanvali    35000	Technical Writer
404  Satish	        30000	Technical writer
405	 Krishna	    30000	Technical Writer
406	 Kiran	        35000	Proof reader

在 Eclipse IDE 中创建一个名为 **JPA_Eclipselink_Criteria** 的 JPA 项目。下面将讨论该项目的所有模块

创建实体

在 **‘src’** 下创建一个名为 **com.tutorialspoint.eclipselink.entity** 的包

在给定的包下创建一个名为 **Employee.java** 的类。Employee 实体类如下所示

package com.tutorialspoint.eclipselink.entity;

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

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

persistence.xml

persistence.xml 文件如下所示

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="Eclipselink_JPA" 
                        transaction-type="RESOURCE_LOCAL">
	<class>com.tutorialspoint.eclipselink.entity.Employee</class>
		<properties>
			<property name="javax.persistence.jdbc.url" 
			          value="jdbc:mysql://127.0.0.1:3306/jpadb"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" 
			          value="root"/>
			<property name="javax.persistence.jdbc.driver" 
			          value="com.mysql.jdbc.Driver"/>
			<property name="eclipselink.logging.level" value="FINE"/>
			<property name="eclipselink.ddl-generation" 
			          value="create-tables"/>
		</properties>
	</persistence-unit>
</persistence>

服务类

此模块包含服务类,这些类使用 MetaData API 初始化来实现 Criteria 查询部分。创建一个名为 **‘com.tutorialspoint.eclipselink.service’** 的包。在给定的包下创建名为 **CriteriaAPI.java** 的类。DAO 类如下所示

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import com.tutorialspoint.eclipselink.entity.Employee;

public class CriteriaApi 
{
	public static void main(String[] args) 
	{
		EntityManagerFactory emfactory = Persistence.
				createEntityManagerFactory( "Eclipselink_JPA" );
		EntityManager entitymanager = emfactory.
				createEntityManager( );
		CriteriaBuilder criteriaBuilder = entitymanager
				.getCriteriaBuilder();
		CriteriaQuery<Object> criteriaQuery = criteriaBuilder
				.createQuery();
		Root<Employee> from = criteriaQuery.from(Employee.class);
		
		//select all records
        System.out.println(“Select all records”);
		CriteriaQuery<Object> select =criteriaQuery.select(from);
		TypedQuery<Object> typedQuery = entitymanager
				.createQuery(select);
		List<Object> resultlist= typedQuery.getResultList();
		
		for(Object o:resultlist)
		{
			Employee e=(Employee)o;
			System.out.println("EID : "+e.getEid()
					+" Ename : "+e.getEname());
		}
		
		//Ordering the records 
        System.out.println(“Select all records by follow ordering”);
		CriteriaQuery<Object> select1 = criteriaQuery.select(from);
        select1.orderBy(criteriaBuilder.asc(from.get("ename")));
        TypedQuery<Object> typedQuery1 = entitymanager
        		.createQuery(select);
        List<Object> resultlist1= typedQuery1.getResultList();
		
		for(Object o:resultlist1)
		{
			Employee e=(Employee)o;
			System.out.println("EID : "+e.getEid()
					+" Ename : "+e.getEname());
		}
		
		entitymanager.close( );
		emfactory.close( );
	}
}

编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板上获得以下输出。

Select All records
EID : 401 Ename : Gopal
EID : 402 Ename : Manisha
EID : 403 Ename : Masthanvali
EID : 404 Ename : Satish
EID : 405 Ename : Krishna
EID : 406 Ename : Kiran
Select All records by follow Ordering
EID : 401 Ename : Gopal
EID : 406 Ename : Kiran
EID : 405 Ename : Krishna
EID : 402 Ename : Manisha
EID : 403 Ename : Masthanvali
EID : 404 Ename : Satish
广告