【JavaWeb】一文学会JPA

简介: 【JavaWeb】一文学会JPA

一、JPA概述


1.JPA概念


JPA(Java Persistence API)是用于对象持久化的API,是Java EE平台标准的ORM规范


,使得应用程序以统一的方式访问持久层。


ORM:


Object Relational Mapping

Java对象与关系数据库之间的映射

JPA:


通过JDK注解或XML描述对象-关系的映射关系

并将运行期的实体对象持久化到数据库中

Sun希望整合ORM技术,统一各种ORM框架的规范,实现天下归一:JPA提供了现有ORM实现框架功能的核心子集

JPA包含三方面的技术


ORM映射元数据:JPA支持XML和JDK注解两种元数据的形式,元数据描述对象和表之间对的映射关系,框架据此将实体对象持久化到数据库表中

JPA的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。

查询语言JPQL:这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。


2.实体


一个实体是一个轻量级的持久化对象。


通常一个实体表示关系数据库中的一张表

实体的每个实例对应表中的一行

假设有一个表名为 user,包含以下字段:



Field

Type

id

INT

name

VARCHAR(100)

age

INT

email

VARCHAR(100)

password

VARCHAR(100)


我们使用JPA定义一个实体类 User,对应 user 表中的一条记录:


@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    private String password;
    // getters and setters
}



在上述代码中,我们使用 @Entity 注解表示这是一个实体类,使用 @Table 注解指定了实体对应的表名为 user。同时,我们在类中定义了实体对应的属性,并使用 @Id 和 @GeneratedValue 注解表示该属性为实体的唯一标识,并指定了该属性的生成策略为自增长。


实体的状态:


新建态new(自由状态):新创建的实体对象,尚未拥有持久化主键,没有和一个持久化上下文关联起来

受控态managed(持久状态):已经拥有持久化主键并和持久化上下文建立了联系

游离态detached(分离状态):拥有持久化主键,但尚未和持久化上下文建立联

删除态removed(删除状态):拥有持久化主键,已经和持久化上下文建立联系系,但已经被安排从数据 库中删除


3.ORM注解


基本注解


@Entity 将对象标注为一个实体,表示需要保存到数据库中


@Table 默认情况下类名即为表名,通过name属性显式指定表名


@Id 对应的属性是表的主键


@GeneratedValue 主键的产生策略,通过strategy属性指定


@EmbeddedId或@IdClass 组合关键字


@Column 属性对应的表字段


@Transient 表示对应属性不需要持久化。在保存或更新实体对象时,该属性不会持 久化到数据库中


关联关系


@OneToOne


@OneToMany


@ManyToOne


@ManyToMany


下面是使用 JPA 实现一对一、一对多、多对一和多对多关系的示例。


一对一关系

在 JPA 中,一对一关系通常使用 @OneToOne 注解来表示。例如,一个 Person 实体可以拥有一个 Passport 实体,如下所示:


@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @OneToOne(mappedBy = "person")
    private Passport passport;
    // getters and setters
}
@Entity
public class Passport {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String number;
    @OneToOne
    @JoinColumn(name = "person_id")
    private Person person;
    // getters and setters
}



上述示例中,Person 实体与 Passport 实体之间建立了一对一的关系,Person 实体拥有一个 Passport 实体,而 Passport 实体则有一个对应的 Person 实体。在 Person 实体中,使用 mappedBy 属性指定了关系的维护方是 Passport 实体,即 Passport 实体维护了这个关系。在 Passport 实体中,使用 @JoinColumn 注解指定了外键列的名称,即 person_id。


一对多关系

在 JPA 中,一对多关系通常使用 @OneToMany 注解来表示。例如,一个 Department 实体可以拥有多个 Employee 实体,如下所示:


@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @OneToMany(mappedBy = "department")
    private List<Employee> employees;
    // getters and setters
}
@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
    // getters and setters
}



上述示例中,Department 实体与 Employee 实体之间建立了一对多的关系,Department 实体拥有多个 Employee 实体,而每个 Employee 实体都对应一个 Department 实体。在 Department 实体中,使用 mappedBy 属性指定了关系的维护方是 Employee 实体,即 Employee 实体维护了这个关系。在 Employee 实体中,使用 @ManyToOne 注解指定了关联的 Department 实体,同时使用 @JoinColumn 注解指定了外键列的名称,即 department_id。


多对一关系

在 JPA 中,多对一关系与一对多关系相反,通常使用 @ManyToOne 注解来表示。例如,一个 Employee 实体可以属于一个 Department 实体,如下所示:


@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    // getters and setters


多对多关系

在 JPA 中,多对多关系通常使用 @ManyToMany 注解来表示。例如,一个 Student 实体可以选修多个 Course 实体,而每个 Course 实体也可以被多个 Student 实体选修,如下所示:


@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "student_course",
            joinColumns = @JoinColumn(name = "student_id"),
            inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses;
    // getters and setters
}
@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @ManyToMany(mappedBy = "courses")
    private List<Student> students;
    // getters and setters
}



上述示例中,Student 实体与 Course 实体之间建立了多对多的关系,一个 Student 实体可以选修多个 Course 实体,而每个 Course 实体也可以被多个 Student 实体选修。在 Student 实体中,使用 @ManyToMany 注解指定了与 Course 实体的关系,并在 JoinTable 注解中指定了关联表的名称,以及关联 Student 实体的主键和 Course 实体的主键。在 Course 实体中,使用 mappedBy 属性指定了关系的维护方是 Student 实体,即 Student 实体维护了这个关系。


需要注意的是,为了避免出现重复的数据,通常使用 CascadeType.PERSIST 和 CascadeType.MERGE 级联操作来保存关联的实体。同时,由于 JoinTable 中的主键是由 Student 实体和 Course 实体组合而成的复合主键,所以需要在 Student 和 Course 实体中实现 equals 和 hashCode 方法,以确保比较两个实体对象时正确性。


4.JPQL


Java Persistence Query Language(Java持久化查询语言)


是一种可移植的查询语言,可以被编译成所有主流数据库服务器 上的SQL

JPQL是面向对象的,通过面向对象而非面向数据库的查询语言查 询数据,在Java空间对类和对象进行操作,避免程序的SQL语句 紧密耦合

使用 javax.persistence.Query接口代表一个查询实例


二、JPA实战


使用JPA持久化对象步骤


创建EntityManagerFactory:创建和销毁都相当耗费资源,通常一个系统内一个数据库仅创建一个。

创建EntityManager

创建实体类,使用注解来描述实体类跟数据库之间的一一映射关系

使用JPA API完成数据增加、删除、修改和查询操作(persisit、remove、merge、find)

假设有一个表名为 user,包含以下字段:



Field

Type

id

INT

name

VARCHAR(100)

age

INT

email

VARCHAR(100)

password

VARCHAR(100)


接下来,我们需要使用 JPA 完成实体类及使用 EntityManager 完成增删改查操作。


首先,我们需要定义一个实体类 User,对应 user 表中的一条记录:


@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    private String password;
    // getters and setters
}



在上述代码中,我们使用 @Entity 注解表示这是一个实体类,使用 @Table 注解指定了实体对应的表名为 user。同时,我们在类中定义了实体对应的属性,并使用 @Id 和 @GeneratedValue 注解表示该属性为实体的唯一标识,并指定了该属性的生成策略为自增长。


接下来,我们可以使用 EntityManager 对实体进行增删改查操作。以下是一个示例:


public class UserDao {
    @PersistenceContext
    private EntityManager entityManager;
    // 添加用户
    public void addUser(User user) {
        entityManager.persist(user);
    }
    // 根据 id 查询用户
    public User getUserById(Integer id) {
        return entityManager.find(User.class, id);
    }
    // 更新用户信息
    public void updateUser(User user) {
        entityManager.merge(user);
    }
    // 根据 id 删除用户
    public void deleteUserById(Integer id) {
        User user = entityManager.find(User.class, id);
        entityManager.remove(user);
    }
}



在上述代码中,我们使用 @PersistenceContext 注解将 EntityManager 注入到 UserDao 类中。接着,我们定义了几个方法,分别用于添加、查询、更新和删除用户。


在 addUser 方法中,我们使用 EntityManager 的 persist 方法将用户对象保存到数据库中。


在 getUserById 方法中,我们使用 EntityManager 的 find 方法根据用户的唯一标识 id 查询用户信息,并将查询结果返回。


在 updateUser 方法中,我们使用 EntityManager 的 merge 方法将修改后的用户对象保存到数据库中。


在 deleteUserById 方法中,我们使用 EntityManager 的 remove 方法将根据用户的唯一标识 id 查询到的用户对象从数据库中删除。


需要注意的是,为了使用 EntityManager,我们需要将 JPA 的实现框架(如 Hibernate)配置到项目中,并在 persistence.xml 配置文件中配置数据源等信息。


三、流行的ORM框架(基于JPA)


1.Hibernate


Hibernate是一个流行的ORM(对象关系映射)框架,它提供了一种方便的方式来映射Java对象与关系型数据库表之间的关系。Hibernate是一个开源框架,可以在Java平台上使用,并支持多种关系型数据库。


Hibernate主要功能包括:


实体映射:Hibernate通过Java注解或XML文件将Java对象映射到数据库表上,实现了Java对象与关系型数据库的映射。开发人员可以通过简单的配置来实现复杂的对象关系映射。

数据库操作:Hibernate提供了一组API,用于执行各种数据库操作,例如插入、更新、删除和查询数据。

事务管理:Hibernate支持事务处理,确保所有数据库操作都可以在事务中进行,以保证数据的完整性和一致性。

缓存管理:Hibernate提供了一些缓存机制,可以减少数据库访问次数,提高性能。

查询语言:Hibernate提供了一种名为HQL(Hibernate Query Language)的查询语言,它允许开发人员以面向对象的方式查询数据库。

除了以上功能,Hibernate还支持诸如延迟加载、级联操作、事件监听、版本控制等高级特性,使得开发人员可以更加灵活地使用Hibernate。Hibernate还有一个称为Hibernate Tools的插件,可以集成到Eclipse等开发工具中,提供一些便捷的工具,帮助开发人员更加高效地使用Hibernate。


Hibernate是一个成熟的ORM框架,在Java开发中得到了广泛应用,也是JPA规范的实现之一。


2.Spring Data JPA


Spring Data JPA是Spring框架中的一个模块,它提供了一种更方便的方式来使用JPA(Java Persistence API)规范。它简化了JPA的使用,并提供了一些便利的功能,如自动生成查询、分页和排序等。使用Spring Data JPA可以减少代码量,提高开发效率。


Spring Data JPA主要功能包括:


Repository接口:Spring Data JPA提供了一个Repository接口,它包含了一组常用的CRUD(Create, Retrieve, Update, Delete)操作,可以用来访问数据库中的数据。开发人员只需定义一个接口继承Repository接口,就可以直接使用这些操作。

自定义查询方法:除了提供常用的CRUD操作外,Spring Data JPA还支持通过方法名来自动生成查询,这样就不需要编写JPQL(Java Persistence Query Language)语句了。例如,如果要根据用户名查询用户信息,可以定义一个名为findByUsername的方法,Spring Data JPA会自动生成查询语句。

分页和排序:Spring Data JPA支持分页和排序,开发人员只需要在Repository接口的方法中传入Pageable对象,就可以实现分页和排序功能。

JPA Criteria查询:Spring Data JPA还支持使用JPA Criteria查询,它可以以面向对象的方式构建动态查询。使用JPA Criteria查询可以提高代码的可维护性和灵活性。

Spring Data JPA是一种非常方便的ORM框架,它可以减少代码量,提高开发效率。它建立在JPA之上,提供了一些便利的功能,使得开发人员可以更加轻松地使用JPA。

相关文章
|
5月前
|
存储 前端开发 JavaScript
基于JavaWeb实现停车场管理系统
基于JavaWeb实现停车场管理系统
|
5月前
|
前端开发 JavaScript Java
图书借阅管理平台|基于JavaWeb实现图书借阅系统
图书借阅管理平台|基于JavaWeb实现图书借阅系统
109 1
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
365 37
|
27天前
|
前端开发 Java 应用服务中间件
Javaweb学习
【10月更文挑战第1天】Javaweb学习
29 2
|
1月前
|
安全 Java Android开发
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
41 5
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
5月前
|
前端开发 Java 关系型数据库
JavaWeb开发简介
JavaWeb开发简介
53 0
|
2月前
|
安全 Java Android开发
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
92 2
|
2月前
|
SQL JSON JavaScript
JavaWeb基础9——VUE,Element&整合Javaweb的商品管理系统
Vue 指令、生命周期、this和$、vue脚手架进行模块化开发/ElementUI框架、综合案例,element商品列表展示增删改查
JavaWeb基础9——VUE,Element&整合Javaweb的商品管理系统
|
5月前
|
SQL Java 数据库连接
JavaWeb Mapper代理开发
JavaWeb Mapper代理开发