JPA讲义

Java持久层API

 

目  录

1      JPA概述.................................................................................................................. 3

1.1      JPA是什么................................................................................................... 3

1.1.1     ORM是什么...................................................................................... 3

1.1.2     标准是什么....................................................................................... 3

1.2      JPA的实现者............................................................................................... 4

1.3      JPA的作用是什么....................................................................................... 4

2      入门示例................................................................................................................ 4

2.1      配置流程图.................................................................................................. 5

2.2      配置步骤说明.............................................................................................. 5

2.3      配置步骤...................................................................................................... 5

2.3.1     第一步:创建Maven项目.............................................................. 6

2.3.2     第二步:创建一个总配置文件....................................................... 7

2.3.3     第三步:封装JPAUtils工具类......................................................... 8

2.3.4     第四步:创建映射实体类............................................................... 8

2.3.5     第五步:在总配置文件中加载映射实体类................................... 9

2.3.6     第六步:操作实体类保存数据..................................................... 10

3      移植Hibernate JPA代码到OpenJPA(了解)................................................... 11

3.1      说明............................................................................................................ 11

3.2      示例代码.................................................................................................... 12

3.2.1     第一步:导入OpenJPA依赖......................................................... 12

3.2.2     第二步:修改总配置文件............................................................. 12

3.3      使用JPA的好处........................................................................................ 13

4      JPA实现CRUD..................................................................................................... 13

5      JPA常用 API说明............................................................................................... 15

5.1      映射注解说明............................................................................................ 15

5.2      JPA常用API说明...................................................................................... 15

6      JPA多表关联查询................................................................................................ 16

6.1      一对多实现................................................................................................ 16

6.1.1     说明................................................................................................. 16

6.1.2     配置步骤......................................................................................... 17

6.2      多对一实现................................................................................................ 20

6.2.1     说明................................................................................................. 20

6.2.2     配置步骤......................................................................................... 20

6.3      双向一对多|多对一(了解).................................................................. 22

6.3.1     说明................................................................................................. 22

6.3.2     配置步骤......................................................................................... 23

6.4      一对一实现................................................................................................ 24

6.4.1     说明................................................................................................. 24

6.4.2     配置步骤......................................................................................... 24

6.5      配置多对多................................................................................................ 28

6.5.1     说明................................................................................................. 28

6.5.2     配置步骤......................................................................................... 28

7      JPA逆向工程........................................................................................................ 33

7.1      说明............................................................................................................ 33

7.2      步骤............................................................................................................ 34

7.2.1     第一步:创建JPA项目.................................................................. 34

7.2.2     第二步:生成JPA代码.................................................................. 35

7.2.3     第三步:导入所需jar依赖........................................................... 43

7.2.4     第四步:更新项目......................................................................... 44

8      JPQL语言............................................................................................................. 44

8.1      说明............................................................................................................ 44

8.2      示例代码.................................................................................................... 44

8.3      JPQL补充:N+1问题............................................................................... 48

1           JPA概述

1.1        JPA是什么

JPA (Java Persistence API) Java持久化API。是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没有实现

 

关注点: ORM  ,标准 概念 (关键字)

 

1.1.1        ORM是什么

ORM(Object Relational Mapping) 对象关系映射。

问:ORM有什么用?

在操作数据库之前,先把数据表与实体类关联起来。 然后通过实体类的对象操作(增删改查)数据库表,这个就是ORM的行为!

所以:ORM是一个实现使用对象操作数据库的设计思想!!!

通过这句话,我们知道JPA的作用就是通过对象操作数据库的,不用编写sql语句。

1.2        JPA的实现者

既然我们说JPA是一套标准,意味着,它只是一套实现ORM理论的接口。没有实现的代码。

那么我们必须要有具体的实现者才可以完成ORM操作功能的实现!

市场上的主流的JPA框架 (实现者)有:

Hibernate (JBoos)、EclipseTop(Eclipse社区)、OpenJPA (Apache基金会)。

其中Hibernate是众多实现者之中,性能最好的。所以,我们本次教学也是选用Hibernate框架作为JPA的主讲框架。

提醒: 学习一个JPA框架,其他的框架都是一样使用

1.3        JPA的作用是什么(问题)

JPA是ORM的一套标准,既然JPA为ORM而生,那么JPA的作用就是实现使用对象操作数据库,不用写SQL!!!.

问题:数据库是用sql操作的,那用对象操作,由谁来产生SQL?

答:JPA实现框架

2           入门示例

任何框架的学习,都建议从配置流程图开始。所以我们来一起理解JPA的配置流程图。

2.1        配置流程图

 

1. 我们需要一个总配置文件persistence.xml存储框架需要的信息 (注意,文件名不要写错,而且必须放在classpath/META-INF文件夹里面)

2. 我们需要一个Persistence持久类对象来读取总配置文件,创建实体管理工厂对象

3. 我们需要实体管理工厂获得数据库的操作对象实体管理对象EntityManager。

4. 我们通过EntityManager操作数据库之前,必须要先配置表与实体类的映射关系,从而实现使用对象操作数据库!!!

2.2        配置步骤说明

第一步:导入包 (不管什么框架,首先要做的事情)

第二步:创建一个总配置文件

第三步:创建一个JPAUtils获得操作对象EntityManager

第四步:创建一个实体类,并且配置好映射注解

第五步:在总配置文件加载实体类

第六步:测试代码(需求:插入数据到用户表)

2.3        配置步骤

需求:编写一个JPA的项目,插入一条数据到学生信息表。

2.3.1        第一步:创建Maven项目

说明:我们这里是基于hibernate实现的,所以要导入Hibernate的JPA规范包

--使用maven构建的配置--

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>cn.zj</groupId>

<artifactId>jpa-demo01-start</artifactId>

<version>0.0.1-SNAPSHOT</version>

<dependencies>

 <!-- hibernate框架实现 JPA 依赖 -->

   <dependency>

       <groupId>org.hibernate</groupId>

       <artifactId>hibernate-entitymanager</artifactId>

       <version>4.3.6.Final</version>

   </dependency>

    <!--jdbc驱动 -->

   <dependency>

      <groupId>mysql</groupId>

      <artifactId>mysql-connector-java</artifactId>

      <version>5.1.40</version>

   </dependency>

</dependencies>

</project>

2.3.2        第二步:创建一个总配置文件

注意:文件必须放在classpath:/META-INF/persistence.xml

 

说明:Eclipse已经支持了JPA框架,所有不需要配置xsd文件,直接使用

 

配置信息如下:

<?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="mysql-jpa">

<!-- 四要素 org.hibernate.cfg.Environment-->

<properties>

<!-- 如果使用Hibernate实现的JPA,使用的就是Hibernate的环境参数 -->

<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />

<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa" />

<property name="hibernate.connection.username" value="root" />

<property name="hibernate.connection.password" value="root" />

<!--可选配置-->

<!--控制台打印sql语句-->

<property name="hibernate.show_sql" value="true" />

<!-- 格式化输出SQL -->

<property name="hibernate.format_sql" value="true" />

</properties>

</persistence-unit>

</persistence>

2.3.3        第三步:封装JPAUtils工具类

创建一个工具类JPAUtils,获得操作对象(EntityManager)

package cn.zj.jpa.util;

import javax.persistence.EntityManager;

import javax.persistence.EntityManagerFactory;

import javax.persistence.Persistence;

public class JPAUtils {

//同一个应用中,应该保证只有一个实例工厂。

public static EntityManagerFactory emf = createEntityManagerFactory();

//1.获得实体管理工厂

private static EntityManagerFactory createEntityManagerFactory(){

EntityManagerFactory emf = Persistence.createEntityManagerFactory("mysql-jpa");

return emf;

}

//2.获得实体管理类对象

public static EntityManager getEntityManger(){

EntityManager entityManager = emf.createEntityManager();

return entityManager;

}

}

2.3.4        第四步:创建映射实体类

创建一个映射的实体类,将JPA的映射注解写在实体类里面。

package cn.zj.jpa.entity;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

//1.指定实体类与表名的关系

//@Entity注解,指定该实体类是一个基于JPA规范的实体类

@Entity

//@Table注解,指定当前实体类关联的表

@Table(name="tb_student")

public class Student {

//@Id注解:声明属性为一个OID属性

@Id

//@GeneratedValue注解,指定主键生成策略

@GeneratedValue(strategy=GenerationType.IDENTITY)

//@Column注解,设置属性与数据库字段的关系,如果属性名和表的字段名相同,可以不设置

@Column(name="stu_id")

private Long stuId;//BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '学生编号',

@Column(name="stu_name")

private String stuName;//VARCHAR(50) NULL DEFAULT NULL COMMENT '学生名字',

@Column(name="stu_age")

private Integer stuAge;//INT(11) NULL DEFAULT NULL COMMENT '学生年龄',

@Column(name="stu_password")

private String stuPassword;//VARCHAR(50) NULL DEFAULT NULL COMMENT '登录密码',

public Student() {

super();

}

//补全get、set方法

}

2.3.5        第五步:在总配置文件中加载映射实体类

<?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="mysql-jpa">

       <!-- 加载实体类

          基于hibernate框架的JPA已经实现了自动载入映射实体类,所以不配置也是可以的。建议还是加上配置。如果不写容易忽略加载的实体类有哪些

         -->

        <class>cn.zj.jpa.entity.Student</class>

<!-- 四要素 org.hibernate.cfg.Environment-->

<properties>

<!-- 如果使用Hibernate实现的JPA,使用的就是Hibernate的环境参数 -->

<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />

<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpa" />

<property name="hibernate.connection.username" value="root" />

<property name="hibernate.connection.password" value="zj" />

<!--可选配置-->

<!--控制台打印sql语句-->

<property name="hibernate.show_sql" value="true" />

<!-- 格式化输出SQL -->

<property name="hibernate.format_sql" value="true" />

</properties>

</persistence-unit>

</persistence>

2.3.6        第六步:操作实体类保存数据

创建一个StudentDAOTest类,测试保存一个学生。

package cn.zj.jpa;

import javax.persistence.EntityManager;

import javax.persistence.EntityTransaction;

import org.junit.Test;

import cn.zj.jpa.entity.Student;

import cn.zj.jpa.util.JPAUtils;

public class StudentDAOTest {

@Test

public void persist(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

//2、获取事物管理器

EntityTransaction transaction = manager.getTransaction();

transaction.begin();

//3、创建实体对象

Student s=new Student();

s.setStuName("张三");

s.setStuAge(18);

s.setStuPassword("zj");

//4、保存到数据库

manager.persist(s);

//5、提交事物

transaction.commit();

//6、关闭资源

manager.close();

}

}

测试结果

 

通过操作实体对象保存数据成功!!!

2.4        使用JPA的好处

使用JPA,可以直接使用对象操作数据库,由框架根据映射的关系生成SQL。不用开发人员编写。这样做,开发人员就不用编写SQL语句了

问题:这样有什么好处呢?

答:不同的数据库的SQL语法是有差异,如果不需要编写SQL语句。就屏蔽各种数据库SQL的差异。那么,编写的代码就可以一套代码兼容多种数据库!!!!

3           JPA实现CRUD

修改StudentDAOTest类,测试crud操作

//通过OID删除

@Test

public void remove(){

//1.获得实体管理类对象

EntityManager entityManager = JPAUtils.getEntityManger();

//2.打开事务

EntityTransaction transaction = entityManager.getTransaction();

//3.启动事务

transaction.begin();

//4.创建数据,删除数据必须使用持久化对象

Student s=entityManager.find(Student.class, 2L);

//5.插入

entityManager.remove(s);;

//6。提交

transaction.commit();

//7.关闭

entityManager.close();

}

//更新

@Test

public void merge(){

//1.获得实体管理类对象

EntityManager entityManager = JPAUtils.getEntityManger();

//2.打开事务

EntityTransaction transaction = entityManager.getTransaction();

//3.启动事务

transaction.begin();

//4.创建数据

Student s=new Student();

s.setStuName("李四");

//更新必须要有一个OID

s.setStuId(3L);

//5.更新

entityManager.merge(s);

//6。提交

transaction.commit();

//7.关闭

entityManager.close();

}

//通过OID获得数据

@Test

public void find(){

//1.获得实体管理类对象

EntityManager entityManager = JPAUtils.getEntityManger();

//通过OID查询数据

Student student = entityManager.find(Student.class, 1L);

System.out.println(student.getStuName());

entityManager.close();

}

//通过OID获得数据

@Test

public void getReference(){

//1.获得实体管理类对象

EntityManager entityManager = JPAUtils.getEntityManger();

/**

* getReference()和find()方法的区别:

* getReference基于懒加载机制,即需要使用对象的时候,才执行查询。

*/

Student student = entityManager.getReference(Student.class, 1L);

System.out.println(student.getStuName());

entityManager.close();

}

4           JPA常用 API说明

4.1        映射注解说明

注解

说明

@Entity

声明该实体类是一个JPA标准的实体类

@Table

指定实体类关联的表,注意如果不写表名,默认使用类名对应表名。

@Column

指定实体类属性对应的表字段,如果属性和字段一致,可以不写

@Id

声明属性是一个OID,对应的一定是数据库的主键字段

@GenerateValue

声明属性(Object ID)的主键生成策略

@SequenceGenerate

使用SEQUENCE策略时,用于设置策略的参数

@TableGenerate

使用TABLE主键策略时,用于设置策略的参数

@JoinTable

关联查询时,表与表是多对多的关系时,指定多对多关联表中间表的参数。

@JoinColumn

关联查询时,表与表是一对一、一对多、多对一以及多对多的关系时,声明表关联的外键字段作为连接表的条件。必须配合关联表的注解一起使用 <key>

@OneToMany

关联表注解,表示对应的实体和本类是一对多的关系

@ManyToOne

关联表注解,表示对应的实体和本类是多对一的关系

@ManyToMany

关联表注解,表示对应的实体和本类是多对多的关系

@OneToOne

关联表注解,表示对应的实体和本类是一对一的关系

4.2        JPA常用API说明

API

说明

Persistence

用于读取配置文件,获得实体管理工厂

EntityManagerFactory

用于管理数据库的连接,获得操作对象实体管理类

EntityManager

实体管理类,用于操作数据库表,操作对象

EntityTransaction

用于管理事务。开始,提交,回滚

TypeQuery

用于操作JPQL的查询的

Query

用于操作JPQL的查询接口,执行没有返回数据的JPQL(增删改)

CriteriaBuilder

用户使用标准查询接口 Criteria查询接口

5           JPA多表关联查询

多个关联查询作用(导航查询):就是实现使用一个实体类对象查询多个表的数据。

配置多表联系查询必须有两个步骤;

1)、在实体类里面建立表与表之间的关系。

2)、在实体类配置关联关系,JPA使用注解配置

 

多表关联的E-R图如下:

 

根据ER图,创建数据库表!!!

5.1        一对多实现 (单向)

需求:通过ID查询一条学生表的记录,同时查询该学生的对应的成绩的信息!

5.1.1        说明

如图所示:一个学生可以有多条成绩的记录,一条成绩的记录只属于一个学生,所以学生表与成绩表的关系是一对多的关系。

 

所以,通过JPA配置一对多的关系,可以通过学生表对应的实体类对象同时获得两个表的数据。

5.1.2        配置步骤

5.1.2.1    第一步:创建项目

说明:复制入门示例的项目即可。

5.1.2.2    第二步:创建单表实体类

(1)创建Student类

@Entity

@Table(name="tb_student")

public class Student {

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="stu_id")

private Long stuId;

@Column(name="stu_name")

private String stuName;

@Column(name="stu_age")

private Integer stuAge;

@Column(name="stu_password")

private String stuPassword;

public Student() {

super();

}

//补全get、set方法

}

(2)创建Score类

@Entity

@Table(name="tb_score")

public class Score{

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="sco_id")

private Long scoId;

@Column(name="sco_subject")

private String scoSubject;

@Column(name="sco_score")

private Float scoScore;

@Column(name="stu_id")

private Long stuId;

public Score() {

super();

}

// 补全getset方法

}

5.1.2.3    第三步:配置一对多关联关系

说明:通过@OneToMany注解配置。

修改Student类,配置一对多关系。

/**

* 单向一对对,应该有学生来维护关系

*

* 一个学生对应多个成绩,一对多关系

* 多个成绩我们使用list封装起来

*

* JPA 使用 @OneToMany 映射一对多

* fetch : 抓取策略

*       FetchType.LAZY 懒加载,默认 (只有关联对象在用到的时候才会去发送新的sql,默认关联对象不会查询)

*           会多生成sql语句 :N+1

*       FetchType.EAGER 迫切查询 (多表连接查询,只会发送一条sql语句)

* @JoinColumn 设置两张表之间外键列

*/

@OneToMany(fetch=FetchType.EAGER)

@JoinColumn(name="stu_id")

private List<Score> scores;

public void setScores(List<Score> scores) {

this.scores = scores;

}

5.1.2.4    第四步:测试一对多查询

@Test

public void testOne2Many(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

Student student = manager.find(Student.class, 1L);

System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

List<Score> scores = student.getScores();

for (Score score : scores) {

System.out.println("科目:"+score.getScoSubject()+",分数:"+score.getScoScore());

}

//6、关闭资源

manager.close();

}

查询结果:

 

一对多关联查询成功!!!

5.2        多对一实现 (单向)

5.2.1        说明

需求:通过ID查询一条成绩表的记录,同时查询该成绩的对应的学生的信息!

如图所示:成绩表里面,每一条记录只能对应一个学生,但是学生编号不是唯一的。所以成绩表里面的多条数据可以对应一个学生,所以我们称多对一的关系。

 

5.2.2        配置步骤

5.2.2.1    第一步:创建项目

复制一对多示例项目即可。

5.2.2.2    第二步:创建单表实体类

修改Student类,去掉一对多配置即可。

5.2.2.3    第三步:配置多对一关联关系

修改Score类,配置多对一关系

@Entity

@Table(name="tb_score")

public class Score{

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="sco_id")

private Long scoId;

@Column(name="sco_subject")

private String scoSubject;

@Column(name="sco_score")

private Float scoScore;

/**

* jpa的多对一,关联关系中指定的外键  和 关联表的属性有冲突

*    解决的方案:去掉关联表中外键对应的属性

/*@Column(name="stu_id")

private Long stuId;

public Long getStuId() {

return stuId;

}

public void setStuId(Long stuId) {

this.stuId = stuId;

}

*/

/**

* 1、分数和学生信息是多对一的关系

* 2、只需要一个学生的实体来引用学生的信息

*/

@ManyToOne

    @JoinColumn(name="stu_id")

    private Student student;

   

    public Student getStudent() {

       return student;

    }

    public void setStudent(Student student) {

       this.student = student;

    }

//补全get、set方法

}

5.2.2.4    第四步:测试

@Test

public void testMany2One(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

Score score = manager.find(Score.class, 1L);

System.out.println("科目:"+score.getScoSubject()+",分数:"+score.getScoScore());

Student student = score.getStudent();

System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

//6、关闭资源

manager.close();

}

查询结果:

 

多对一配置成功!!!

5.3        双向一对多|多对一(了解)

5.3.1        说明

(1)查询学生信息,同时查询成绩信息。

(2)查询成绩信息,同时也可以查询学生信息。

5.3.2        配置步骤

在同一个项目中,在Student类和Score类中,同时配置关联关系。

(1)在Student类中配置一对多

@OneToMany   //声明是一对多的关系

@JoinColumn(name="stu_id")   //指定关联表中  外键的字段

private List<Score> scores;

public List<Score> getScores() {

return scores;

}

public void setScores(List<Score> scores) {

this.scores = scores;

}

(2)在Score类中配置多对一

/**

* jpa的多对一,关联关系中指定的外键  和 关联表的属性有冲突

*    解决的方案:去掉关联表中外键对应的属性

@Column(name="stu_id")

private Long stuId;

public Long getStuId() {

return stuId;

}

public void setStuId(Long stuId) {

this.stuId = stuId;

}

*/

/**

* 1、分数和学生信息是多对一的关系

* 2、只需要一个学生的实体来引用学生的信息

*/

@ManyToOne

@JoinColumn(name="stu_id")

private Student student;

public Student getStudent() {

return student;

}

public void setStudent(Student student) {

this.student = student;

}

5.4        一对一实现

5.4.1        说明

需求:通过ID查询学生的信息,通过也获得学生对应的学生身份信息。

 

5.4.2        配置步骤

5.4.2.1    第一步:创建项目

复制一对多的示例项目即可。

5.4.2.2    第二步:创建单表实体类

(1)创建Student类

(2)创建Identity类

package cn.zj.jpa.entity;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.Id;

import javax.persistence.Table;

@Entity

@Table(name="tb_identity")

public class Identity {

@Id

/*由于一对一,外键表的主键字段值来自于主键表,所以只能手工输入

手工输入ID值,可以不指定主键生成策略 */

//  @GeneratedValue

@Column(name="stu_id")

private Long stuId;

@Column(name="stu_identity")

private String stuIdentity;

@Column(name="stu_no")

private String stuNo;

public Identity() {

super();

}

//  补全get、set方法

}

5.4.2.3    第三步:配置一对一关联关系

说明:一对一关联关系,也是支持双向配置的。

可以在Student类、Identity类中同时配置关联关系。

(1)修改Student类,配置一对一关系。

//学生表与学生身份表是一对一的关系,意味着,一个学生只能对应一条学生身份信息

//所以使用引用

//1.声明关系,一对一

@OneToOne

//2.必须要指定关联的外键

@JoinColumn(name="stu_id")

private Identity identity;

public Identity getIdentity() {

return identity;

}

public void setiIdentity(Identity identity) {

this.identity = identity;

}

(2)修改Score类

//1.声明关系,一对一

@OneToOne

//2.指定关联的外键

@JoinColumn(name="stu_id")

private Student student;

public Student getStudent() {

return student;

}

public void setStudent(Student student) {

this.student = student;

}

5.4.2.4    第四步:测试

说明:可以分别测试方向一对一关系。

@Test

public void testOne2One1(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

Student student = manager.find(Student.class, 1L);

System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

Identity identity = student.getIdentity();

System.out.println("学生学号:"+identity.getStuNo()+",身份证号:"+identity.getStuIdentity());

//6、关闭资源

manager.close();

}

@Test

public void testOne2One2(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

Identity identity = manager.find(Identity.class, 1L);

System.out.println("学生学号:"+identity.getStuNo()+",身份证号:"+identity.getStuIdentity());

Student student = identity.getStudent();

System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

//6、关闭资源

manager.close();

}

(1)测试学生关联身份信息

测试结果:

 

(2)测试身份信息关联学生。

 

一对一配置成功!!!

5.5        配置多对多

5.5.1        说明

需求:

(1)通过ID查询学生的信息,通过该学生信息也获得对应的教师信息。

(2)通过ID查询教师的信息,通过教师信息也获得该对应的学生信息。

如图所示:一个学生可以有多个教师,一个教师也可以有多个学生,所以学生和教师的关系是多对多的关系。

 

如上图所示:

如果要从学生表的信息获得教师表的信息。必须需要三个条件

1. 必须需要有一个中间表

2. 必须需要中间表对应本表的外键

3. 必须需要中间表对应关联表的外键

5.5.2        配置步骤

5.5.2.1    第一步:创建项目

复制一个示例项目即可。

5.5.2.2    第二步:创建单表实体类

学生实体类Student

//1.指定实体类与表名的关系

//@Entity注解,指定该实体类是一个基于JPA规范的实体类

@Entity

//@Table注解,指定当前实体类关联的表

@Table(name="tb_student")

public class Student {

//@Id注解:声明属性为一个OID属性

@Id

//@GeneratedValue注解,指定主键生成策略

@GeneratedValue(strategy=GenerationType.IDENTITY)

//@Column注解,设置属性与数据库字段的关系,如果属性名和表的字段名相同,可以不设置

@Column(name="stu_id")

private Long stuId;//BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '学生编号',

@Column(name="stu_name")

private String stuName;//VARCHAR(50) NULL DEFAULT NULL COMMENT '学生名字',

@Column(name="stu_age")

private Integer stuAge;//INT(11) NULL DEFAULT NULL COMMENT '学生年龄',

@Column(name="stu_password")

private String stuPassword;//VARCHAR(50) NULL DEFAULT NULL COMMENT '登录密码',

public Student() {

super();

}

//补全get、set方法

}

教师实体类Teacher

@Entity

@Table(name="tb_teacher")

public class Teacher {

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name="tea_id")

private Long teaId;

@Column(name="tea_name")

private String teaName;

@Column(name="tea_password")

private String teaPassword;

public Teacher() {

super();

}

//补全get、set方法

}

5.5.2.3    第三步:配置多对多关系

(1)学生关联教师,修改Student类

// 学生表和教师表是多对多的关系

// 所以,一个学生可以有多个教师,所以需要使用集合来存储教师信息

//1.声明关系,多对多

@ManyToMany

//2.设置关联的条件

//JoinTable用于对应中间表的设置     joinColumns设置中间表与本表关联的外键    inverseJoinColumns设置中间表与关联表对应的外键

@JoinTable(name="tb_stu_tea" ,joinColumns=@JoinColumn(name="stu_id"),inverseJoinColumns=@JoinColumn(name="tea_id"))

private List<Teacher> teachers;

public List<Teacher> getTeachers() {

return teachers;

}

public void setTeachers(List<Teacher> teachers) {

this.teachers = teachers;

}

(2)教师关联学生,修改Teacher类

//因为教师与学生是多对多的关系,所以一个教师也可以有多个学生,需要使用集合来存储学生的数据

//1.声明教师和学生的关系,多对多

@ManyToMany

//2.设置关联的条件

@JoinTable(name="tb_stu_tea" ,joinColumns=@JoinColumn(name="tea_id"),inverseJoinColumns=@JoinColumn(name="stu_id"))

private List<Student> students;

public List<Student> getStudents() {

return students;

}

public void setStudents(List<Student> students) {

this.students = students;

}

5.5.2.4    测试

5.5.2.4.1    Step1:测试学生关联教师

测试代码

@Test

public void testMany2Many1(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

Student student = manager.find(Student.class, 1L);

System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

List<Teacher> teachers = student.getTeachers();

for (Teacher teacher : teachers) {

System.out.println("教师id:"+teacher.getTeaId()+",教师姓名:"+teacher.getTeaName());

}

//2、关闭资源

manager.close();

}

测试结果:

 
5.5.2.4.2    Step2:测试教师关联学生

测试代码

@Test

public void testMany2Many2(){

//1.获得实体管理类

EntityManager manager = JPAUtils.getEntityManger();

Teacher teacher = manager.find(Teacher.class, 1L);

System.out.println("教师id:"+teacher.getTeaId()+",教师姓名:"+teacher.getTeaName());

List<Student> students = teacher.getStudents();

for (Student student : students) {

System.out.println("学生id:"+student.getStuId()+",学生姓名:"+student.getStuName());

}

//2、关闭资源

manager.close();

}

测试结果:

 

多对多配置成功!!!

6           JPA逆向工程

6.1        说明

所谓的逆向工程就是通过数据库的结构生成代码。

目的:提高开发的效率

 

6.2        步骤

6.2.1        第一步:创建JPA项目

(1)创建项目

 

(2)指定项目名、JPA版本

 

(3)完成创建

 

6.2.2        第二步:生成JPA代码

右击项目的src文件夹,选择new --> Other.. -->JPA的JPA Entities from Tables

6.2.2.1    Step1:创建新的数据库连接

(1)选择新建数据库连接

 

(2)指定数据库类型

 

(3)新建数据库驱动

 

(4)配置驱动信息

驱动版本号

 

加载驱动jar包

 

配置jdbc四要素

 

6.2.2.2    Step2:配置表与表直接的关联关系

(1)配置表关联关系

选择表,全选即可。

 

配置Student、Score一对多

依次配置其它的关联关系即可。

 

6.2.2.3    Step3:指定生成实体类的名称及结构

(1)修改关联对象的属性名

 

指定实体类的生成属性

 

指定实体类的类名

 

依次修改其它类的属性即可。

6.2.2.4    Step4:生成代码

 

6.2.3        第三步:导入所需jar依赖

说明:Maven项目是可以导入jar包到本地的。

方法:打开DOS窗口,进入项目的pom文件所在目录,执行命令:

mvn dependency:copy-dependencies

前提:已经配置了Maven环境变量。

 

6.2.4        第四步:更新项目

 

7           JPQL语言

7.1        说明

JPQL : Java Persistence Query Language : java持久化查询语言。

它的作用是通过类似SQL的语法去操作实体类的对象。

语法和SQL一样的,SQL操作的数据表,JPQL操作的对象

作用:实现个性化的查询需求

7.2        示例代码

package cn.zj.jpa;

import java.util.List;

import javax.persistence.EntityManager;

import javax.persistence.EntityTransaction;

import javax.persistence.Query;

import javax.persistence.TypedQuery;

import org.junit.Test;

import cn.zj.jpa.entity.Student;

import cn.zj.jpa.util.JPAUtils;

public class StudentDAOTest {

//1.查询所有学生的信息

@Test

public void findAll(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

//2.获得JPQL查询对象

//标准的JPQL是必须要使用select

//select语法: select 别名  from 类名 别名

TypedQuery<Student> query = manager.createQuery("select s from Student s", Student.class);

//返回多条查询的数据,getResultList

//TypedQuery解决了HIbernate返回有警告的问题

List<Student> students = query.getResultList();

for (Student student : students) {

System.out.println("学生名:"+student.getStuName());

}

manager.close();

}

//2.条件查询

//需求:查询名字有张字的学生

//注意:JPQL的语法,使用?设置参数,必须要在?后面设置下标值,下标值不能为负数

@Test

public void findByCondition(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

//2.获得JPQL查询对象

//标准的JPQL是必须要使用select

TypedQuery<Student> query = manager.createQuery("select s from Student s where s.stuName like ?1", Student.class);

//3.设置条件

query.setParameter(1, "%张%");

List<Student> students = query.getResultList();

for (Student student : students) {

System.out.println("学生名:"+student.getStuName());

}

manager.close();

}

@Test

public void findByCondition1(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

//2.获得JPQL查询对象

//标准的JPQL是必须要使用select

TypedQuery<Student> query = manager.createQuery("select s from Student s where s.stuName like :stuName", Student.class);

//3.设置条件

query.setParameter("stuName", "%张%");

List<Student> students = query.getResultList();

for (Student student : students) {

System.out.println("学生名:"+student.getStuName());

}

manager.close();

}

//需求:返回学生表的记录数

@Test

public void count(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

//2.获得JPQL查询对象

//标准的JPQL是必须要使用select

//JPQL中的count操作返回值是Long值,所以用Long类型接收

TypedQuery<Long> query = manager.createQuery("select count(s) from Student s", Long.class);

//如果返回的是一个值的查询,使用getSingleResult

Long count = query.getSingleResult();

System.out.println(count);

manager.close();

}

//需求:第二页,每页三条

@Test

public void findByPage(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

//2.获得JPQL查询对象

//标准的JPQL是必须要使用select

TypedQuery<Student> query = manager.createQuery("select s from Student s", Student.class);

//设置分页条件

//1.设置开始位置,下标从0开始,第四条数据的下标为3

query.setFirstResult(3);

//2.设置每页的记录

query.setMaxResults(3);

List<Student> students = query.getResultList();

for (Student student : students) {

System.out.println("学生名:"+student.getStuName());

}

manager.close();

}

/*

* 命名查询语句的调用

*

* 所谓的命名查询,就是在实体类对象使用一个名字声明一条JPQL语句

* 这样可以通过name值获得Query的语句

*

* 命名查询,在类名上做如下声明:

@NamedQuery(name="Student.findAll", query="SELECT s FROM Student s")

public class Student {

*/

@Test

public void findAllByNamedQuery(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

//2.获得一个查询命名查询语句的对象

//可以通过该对象调用实体类声明的命名查询语句

TypedQuery<Student> query = manager.createNamedQuery("Student.findAll", Student.class);

List<Student> students = query.getResultList();

for (Student student : students) {

System.out.println(student.getStuName());

}

manager.close();

}

//需求:通过JQOL删除有张字的学生

@Test

public void removeByCondition(){

//1获得操作对象

EntityManager manager = JPAUtils.getEntityManager();

EntityTransaction transaction = manager.getTransaction();

transaction.begin();

try {

//2.获得JPQL查询对象

//注意,调用操作的JPQL是不需要指定返回的类型

Query query = manager.createQuery("delete from Student s where s.stuName like ?1");

//参数对应?设置的下标值

query.setParameter(1, "%张%");

int count = query.executeUpdate();

System.out.println(count);

transaction.commit();

manager.close();

} catch (Exception e) {

transaction.rollback();

e.printStackTrace();

}

}

}

7.3        JPQL补充:N+1问题

在一对多或者多对多查询过程中,首先查询1这一方的数据,然后根据1这一份的数据,查询多的一方的数据。

当学生有N个的时候,总共查询次数N+1次。

这个就称之为N+1问题

当我们数据库的量不大的时候,N+1问题基本没有什么影响。如果当数据量很大的时候,查询数据库的次数,就很大了,这个就会影响数据库的性能。

如何解决这个问题?

可以通过JPQL来解决。

@Test

public void one2manybyOne(){

//1、获取实体操作对象

EntityManager manager = JPAUtils.getEntityManager();

//JPQL是通过fetch这个关键词,在查询学生的信息的时候,一起将分数也查询出来

//最终执行的sql就只有一条

TypedQuery<Student> query = manager.createQuery("select distinct s from Student s inner join fetch s.scores", Student.class);

List<Student> students = query.getResultList();

for (Student student : students) {

System.out.println("学生姓名:"+student.getStuName()+",学生id:"+student.getStuId());

List<Score> scores = student.getScores();

for (Score score : scores) {

System.out.println("科目:"+score.getScoSubject()+",分数:"+score.getScoScore());

}

System.out.println("---------------------------------");

}

}

执行结果:

 

执行过程中,确实一条sql语句!!!

解决了频繁查询数据库,带来的数据库性能损耗。

转载于:https://www.cnblogs.com/meizhoulqp/p/11313430.html

JPA---Java持久层API相关推荐

  1. java hibernate的使用_《Hibernate快速开始 – 4 – 使用JAVA持久层 API (JPA)教程》

    章节目标 使用JPA EntityManagerFactory 使用注解提供映射信息 使用 JPA 接口 本教程可在 entitymanger/ 路径下下载 4.1. persistence.xml ...

  2. Spring Data JPA的持久层

    1.概述 本文将重点介绍Spring 3.1,JPA和Spring Data的持久层的配置和实现. 有关使用基于Java的配置和项目的基本Maven pom设置Spring上下文的分步介绍,请参阅本文 ...

  3. Java 持久层概述

    JDBC Java Database Connectivity 是一系列接口规范.Java 程序都是通过 JDBC 连接数据库的.然后通过其执行SQL.对数据库进行操作. DBC 只是 Sun 公司定 ...

  4. java持久层用文件_Java持久层框架MyBatis简单实例

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .本文 ...

  5. mybatis(java持久层框架)

    mybatis java持久层框架 (对JDBC进行封装,并自动完成ORM操作) ORM框架是对象关系映射,一个对象与表中的一行数据一一对应,把对象持久化到数据库中. 我将会一步一步详细的创建一个完整 ...

  6. MiniDao (轻量级JAVA持久层,Hibernate完美助手)

    MiniDao (轻量级JAVA持久层,Hibernate完美助手) 当前最新版本: 1.6.4 (发布日期:20180604) MiniDao产生的初衷? 采用Hibernate的J2EE项目都有一 ...

  7. Java持久层框架之mybatis使用

    一.什么是框架,框架从何而来,为什么使用框架? 框架(framework): 1.是一系列jar包,其本质是对JDK功能的拓展.(jar包,jar:class文件的压缩包) 2.框架是一组程序的集合, ...

  8. java持久层框架mybatis如何防止sql注入

    2019独角兽企业重金招聘Python工程师标准>>> sql注入大家都不陌生,是一种常见的攻击方式,攻击者在界面的表单信息或url上输入一些奇怪的sql片段,例如"or ...

  9. java 实体类 临时注解_JPA:Java持久层API--配置流程

    一.JPA概述 1.1 JPA是什么 JPA (Java Persistence API) Java持久化API.是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没 ...

最新文章

  1. 知乎高赞:我的编程能力从什么时候开始突飞猛进的?
  2. SpringBoot任务调度案例(学习笔记)
  3. Gossip协议详解
  4. 解析提高PHP执行效率的50个技巧(转)
  5. jsf tree组件_JSF:在传统组件和时尚性能杀手之间进行选择
  6. 脚本启动显示查询频繁被服务器防御_又被CC攻击弄得心有余悸?莫怕!这里教你如何防御...
  7. linux免费计费系统下载,思谷电话计费系统 Linux版
  8. 算法训练营 重编码_关于如何在没有训练营的情况下学习编码的10条提示
  9. 2006中国最令人失望的十所大学
  10. 配置LANMP环境(1)-- 安装虚拟机VMware与安装CentOS7.2系统
  11. 国内十大主流安卓和iOSApp应用商店推广渠道列表
  12. js 获取屏幕高宽_js获取屏幕高度宽度
  13. js获取移动端屏幕高度和宽度等设备尺寸
  14. 计算机工控机配置,研华工控机最新配置IPC-610
  15. ECSHOP二次开发之心得体验
  16. 点赞 分数 20作者 陈越单位 浙江大学
  17. Electron编译报错:include: could not find: ****StdUtils.nsh“的解决
  18. linux gianfar 网口驱动源码,基于MPC8313ERDB平台的Marvell88E1111型网卡驱动移植(uboot+kernel)...
  19. 李涛Photoshop笔记之基础篇
  20. 通信电子电路(二十三)习题讲解 第五章

热门文章

  1. python游戏开发实战:梦幻西游背包系统
  2. 电阻的固有噪声(热噪声)
  3. kk 凯文·凯利 《失控》读后
  4. 【字符识别】基于matlab GUI模板匹配(区域生长法)字母+数字识别【含Matlab源码 1695期】
  5. 2022年华为ICT实践赛网络赛道题库全(1107道题目)
  6. DPDK的igb_uio内核态和用户态实现
  7. Android Camera2拍照录制工具
  8. Levenberg-Marquardt(LM算法)的理解
  9. tplink android管理软件,TPLINK智能家居
  10. vue-cli项目引入字体包