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

一、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实现框架 

二、 入门示例

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

2.1 配置流程图

2f0913d5cd38cb513780228e33d3efc8.png
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文件,直接使用

9e6cc217fa4a707718986314053b1766.png

配置信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="Java Persistence API: XML Schemas" 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="Java Persistence API: XML Schemas" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="Java Persistence API: XML Schemas 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 {@Testpublic 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(); } 
}

测试结果

a92fe813cfdbdbdfc6007850734b59c5.png

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

2.4 使用JPA的好处

使用JPA,可以直接使用对象操作数据库,由框架根据映射的关系生成SQL。不用开发人员编写。这样做,开发人员就不用编写SQL语句了。 
问题:这样有什么好处呢? 
答:不同的数据库的SQL语法是有差异,如果不需要编写SQL语句。就屏蔽各种数据库SQL的差异。那么,编写的代码就可以一套代码兼容多种数据库!!!! 

三、JPA实现CRUD

修改StudentDAOTest类,测试crud操作

//通过OID删除@Testpublic 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();}//更新@Testpublic void merge(){//1.获得实体管理类对象EntityManager entityManager = JPAUtils.getEntityManger();//2.打开事务EntityTransaction transaction = entityManager.getTransaction();//3.启动事务transaction.begin();//4.创建数据Student s=new Student();s.setStuName("李四");//更新必须要有一个OIDs.setStuId(3L);//5.更新entityManager.merge(s);//6。提交transaction.commit();//7.关闭entityManager.close();}//通过OID获得数据@Testpublic void find(){//1.获得实体管理类对象EntityManager entityManager = JPAUtils.getEntityManger();//通过OID查询数据Student student = entityManager.find(Student.class, 1L);System.out.println(student.getStuName());entityManager.close();}//通过OID获得数据@Testpublic void getReference(){//1.获得实体管理类对象EntityManager entityManager = JPAUtils.getEntityManger();/*** getReference()和find()方法的区别:* getReference基于懒加载机制,即需要使用对象的时候,才执行查询。*/Student student = entityManager.getReference(Student.class, 1L);System.out.println(student.getStuName());entityManager.close();}

四、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查询接口

五、JPA多表关联查询

多个关联查询作用(导航查询):就是实现使用一个实体类对象查询多个表的数据。 配置多表联系查询必须有两个步骤; 
(1)、在实体类里面建立表与表之间的关系。 
(2)、在实体类配置关联关系,JPA使用注解配置 

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

6d2aaec53ea3f976aa312f71e26a0bf3.png

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

5.1 一对多实现 (单向)

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

5.1.1 说明

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

8e117813a44c360036d2392d8548c9fe.png

所以,通过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();}
// 补全get、set方法
}

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(); 
}

查询结果:

0daa4208d9dd2249b95dca1bebb9c688.png

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

5.2 多对一实现 (单向)

5.2.1 说明

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

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

9c2de6273d0c1ec41fd40baee3f20009.png

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 第四步:测试

@Testpublic 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(); }

查询结果:

9148e441736c4633dbe39f32b1102f68.png

多对一配置成功!!!

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查询学生的信息,通过也获得学生对应的学生身份信息。

7044e010ec540b0105628aa88e8a81be.png

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 第四步:测试

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

@Testpublic 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(); }@Testpublic 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)测试学生关联身份信息

测试结果:

c7ffe9b82306d5678c1848575825a564.png

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

c0225682bc799e85ee63d70d398ac8cc.png

一对一配置成功!!!

5.5 配置多对多

5.5.1 说明

需求:

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

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

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

1341fc502b7abf4fd7d7703aa9d8b718.png

如上图所示:

如果要从学生表的信息获得教师表的信息。必须需要三个条件 
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:测试学生关联教师

测试代码

@Testpublic 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(); }

测试结果:

9d3ccb48b9d1e7deb78eda71fb82eaed.png

5.5.2.4.2 Step2:测试教师关联学生

测试代码

@Testpublic 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(); }

测试结果:

723004a5ad04e28fe373d2b9db10a9cc.png

多对多配置成功!!!

六、JPA逆向工程

6.1 说明

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

目的:提高开发的效率

d0a71988fdb3f639361ae6558f0b2a77.png

6.2 步骤

6.2.1 第一步:创建JPA项目

(1)创建项目

52ccc404b2cb77543f417708011bdd37.png

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

4fe2ba1c490fe7227674bc4d444ac3ef.png

(3)完成创建

dbfc20165fe3e1c90eeb32f81c9d7991.png

6.2.2 第二步:生成JPA代码

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

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

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

4d299b32d711f5c7e34a686cc1c8d2c8.png

(2)指定数据库类型

b188e6a87cb2d8aa2e07ad3160a5d100.png

(3)新建数据库驱动

bd661a50bc1ca95f931e73661f53dd12.png

(4)配置驱动信息

驱动版本号

3af94f7c1ccfbab318ef458c0d476f9a.png

加载驱动jar包

cae3d30527aea08fd760885ff499e091.png

配置jdbc四要素

452fccfc1cba5d5ba64b588c661860c6.png

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

(1)配置表关联关系

选择表,全选即可。

bb3d83f161b62e6c5f93955fbfd2fdf4.png

配置Student、Score一对多

04d131670a98f323f6758b2112c32655.png

776322f0033e4768ebd8a0a38303aae4.png

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

fa4996be9c1f79875a3d8171784cbfb4.png

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

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

d97784bad42693783671550e2a23529b.png

指定实体类的生成属性

4653d9ff341c564a51ba861b8393d23b.png

指定实体类的类名

4f765b9527a830034fe710513ec5a126.png

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

6.2.2.4 Step4:生成代码

197a9931ab9f9276285d1fd7de162222.png

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

说明:Maven项目是可以导入jar包到本地的。
方法:打开DOS窗口,进入项目的pom文件所在目录,执行命令:
mvn dependency:copy-dependencies
前提:已经配置了Maven环境变量。

fe0dfdda2d1ecb04aca05223b7df208e.png

6.2.4 第四步:更新项目

cf2926ab2df36bfcf126e14aaec83cbb.png

七、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来解决。

@Testpublic 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("---------------------------------");}}

执行结果:

459ad7d83a2a76b4f8fa2ed6bc4c0508.png

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/245547.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android新架构,Android新架构组件 LifeCycles 简介

一、前言为了使开发者能尽快在 Android 平台上开发出高质量的项目&#xff0c;Android 官方推出了 Android Jetpack 项目&#xff0c;旨在从基础&#xff0c;架构&#xff0c;行为以及界面 4 大方面体系化地为我们提供组件级别的支持。当然&#xff0c;在实际开发过程中&#x…

领域驱动设计 pdf_什么是领域驱动设计?

什么是领域驱动设计&#xff1f;你可能使用领域驱动设计(DDD)开发了一些项目。你可能很满意&#xff0c; 使用领域模型来开发领域业务。并且得意地展示给你的同事看&#xff0c;他们会说“666”。但有的时候你使用领域模型你总觉得哪儿有点不对劲。你会嘀咕你可能遗漏了什么。 …

Android四级缓存,RecyclerView 源码四级缓存原理

入口我们从使用功能上去读取源码&#xff0c;通常的用法是这个样子-> 我们设置layoutmanager&#xff0c;GridLayouManager 继承LinearLayoutManager&#xff0c;所以我们就LinearLayoutManager 为基准查看rv.layoutManager GridLayoutManager(this,5)rv.addItemDecoration…

shell脚本发邮件内容html,[转]Shell脚本中发送html邮件的方法

作为运维人员&#xff0c;免不了要编写一些监控脚本&#xff0c;并将监控结果及时的发送出来。那么通过邮件发送是比较常用的一种通知方式了。通常的&#xff0c;如果需要发送的内容是简单的文本文件&#xff0c;那么使用/bin/mailx就可以了&#xff0c;但是如果想要发送更复杂…

HTML打开网页拒绝访问,192.168.1.1拒绝访问怎么办?

问&#xff1a;为什么设置路由器时&#xff0c;在浏览器中输入192.168.1.1&#xff0c;结果显示拒绝访问&#xff0c;这个问题怎么解决&#xff1f;答&#xff1a;如果是在设置路由器的时候&#xff0c;登录192.168.1.1被拒绝访问&#xff0c;多半是你自己操作有问题导致的&…

gitlab git clone 输入密码_gitlab1:部署gitlab

1、配置yum源vim /etc/yum.repos.d/gitlab-ce.repo复制以下内容&#xff1a;[gitlab-ce]nameGitlab CE Repositorybaseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/gpgcheck0enabled12、更新本地yum缓存sudo yum makecache3、安装GitLab社区版sudo y…

python播放在线音乐_Python实现在线音乐播放器

最近这几天&#xff0c;学习了一下python&#xff0c;对于爬虫比较感兴趣&#xff0c;就做了一个简单的爬虫项目&#xff0c;使用Python的库Tkinsert做了一个界面&#xff0c;感觉这个库使用起来还是挺方便的&#xff0c;音乐的数据来自网易云音乐的一个接口&#xff0c;通过re…

golang如何打印float64的整数部分_2020-08-10:如何不用加减乘除求浮点数的2倍值?...

福哥答案2020-08-10&#xff1a;浮点数符号位阶码尾数&#xff0c;阶码加1就是浮点数的2倍值。代码用golang编写&#xff0c;如下&#xff1a;package test33_addimport ( "fmt" "math" "testing")/*//https://www.bbsmax.com/A/6pdDX7…

mysql varchar 非空判断_工资从1万到3万,你还差mysql数据库优化之系列三

查询性能的优化优化查询分析的步骤:1.应用查询是否检索超过需要的数据2.mysql服务器是否在分析超过需要的数据正确使用索引:1.like语句操作一般不使用%或_开头例如: select * from tableName where name like %cn;只能使用like aaa%;2.组合索引例如索引index index_name (a, b,…

etl数据抽取工具_数据同步工具ETL、ELT傻傻分不清楚?3分钟看懂两者区别

什么是数据同步工具(ETL、ELT)数据同步工具ETL或者ELT的作用是将业务系统的数据经过抽取、清洗转换之后加载到数据仓库的过程&#xff0c;目的是将企业中的分散、零乱、标准不统一的数据整合到一起&#xff0c;为企业的决策提供分析依据。数据同步是大数据项目重要的一个环节。…

oracle数据库查表_Oracle面试问题-技术篇

这也许是你一直期待的文章&#xff0c;在关注这部分技术问题的同时&#xff0c;请务必阅读有关面试中有关个人的问题和解答。和猎萝卜小编来一起了解。这里的回答并不是十分全面&#xff0c;这些问题可以通过多个角度来进行解释&#xff0c;也许你不必在面试过程中给出完全详尽…

uniapp怎么调起摄像头拍视频_抖音视频怎么拍?我们总结了10个手机视频拍摄小技巧...

抖音的很多功能与小咖秀类似,但不同的是,抖音用户可以通过视频拍摄的快慢、视频编辑和特效等技术让作品更具创造性,而不是简单地对嘴型。抖音短视频的10个拍摄技巧,帮助你方便、快捷地制作出更加优质的短视频内容。1.远程控制暂停更方便抖音视频怎么拍&#xff1f;在拍摄时,如果…

jdk 安装_Jdk 安装使用教程

java 程序员的第一个程序 hello worldpublic class MyFirstJavaProgram {public static void main(String []args) {System.out.println("Hello World");}}1、下载jdk连接地址&#xff1a;https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_o…

win10计算机管理字体糊,win10字体模糊如何解决

win10系统是一款优秀的消费级别的系统&#xff0c;深受大家广泛好评。但是有些网友在使用时也会出现一些问题&#xff0c;比如win10字体模糊。接下来&#xff0c;我就给大家介绍一下解决win10字体模糊的解决方法&#xff0c;赶紧来瞧瞧吧近来有不少网友询问win10字体模糊的解决…

蓝字冲销是什么意思_梦见上学 做梦梦到上学是什么意思 梦到上学有哪些预兆...

点击上方蓝字关注我们 查看更多梦见上学是什么意思 做梦梦到上学是什么意思 梦到上学有哪些预兆梦见上学 做梦梦到念书是什么意思 梦见上学代表什么意思预兆梦见上学&#xff0c;吉兆&#xff0c;生活会幸福快乐。梦见上学&#xff0c;可能是因为你近期的生活工作压力导致的&am…

ffmpeg如何在结尾添加帧_一种“视频帧对齐”的测试方案实践

点击蓝字?关注【测试先锋】&#xff0c;不再迷路&#xff01;一起成为互联网测试精英&#xff0c;前瞻测试技术&#xff5e;导语全参考清晰度测算的时候&#xff0c;输入两个视频帧序列&#xff0c;但是视频帧序列没有对齐&#xff0c;怎么知道丢了哪帧&#xff1f;又怎么知道…

java mongo分组统计_探秘 Dubbo 的度量统计基础设施 - Dubbo Metrics

对服务进行实时监控&#xff0c;了解服务当前的运行指标和健康状态&#xff0c;是微服务体系中不可或缺的环节。Metrics 作为微服务的重要组件&#xff0c;为服务的监控提供了全面的数据基础。近日&#xff0c;Dubbo Metrics 发布了2.0.1版本&#xff0c;本文将为您探秘 Dubbo …

python可以做运动控制卡吗_今天,终于明白了运动控制器和运动控制卡的区别

原标题&#xff1a;今天&#xff0c;终于明白了运动控制器和运动控制卡的区别 运动控制器是完整的、独立的硬件平台&#xff0c;运动控制卡则需要一个载体(一个系统运行平台&#xff0c;必须基于PC)。 一、从安装使用方式来看 运动控制卡&#xff0c;一般是PCI插槽的&#xff0…

电子计算机技能竞赛数据,2015年浙江省中等职业学校计算机应用技术专业学生职业技能大赛“计算机检测维修与数据恢复”赛项规程.doc...

2015年浙江省中等职业学校计算机应用技术专业学生职业技能大赛“计算机检测维修与数据恢复”赛项规程.doc还剩8页未读&#xff0c;继续阅读下载文档到电脑&#xff0c;马上远离加班熬夜&#xff01;亲&#xff0c;喜欢就下载吧&#xff0c;价低环保&#xff01;内容要点&#x…

设备的dpr_湘潭污水处理设备_处理污水设备生产厂

湘潭污水处理设备_处理污水设备生产厂?氮磷过度排放导致水体富营养化仍是全球关注的水污染热点问题, 而对于传统城市污水处理厂来说, 污水的深度脱氮除磷和同步达标排放仍是需要攻克的难点问题.传统脱氮除磷工艺存在脱氮与除磷对有限碳源的竞争、硝化反应产物对厌氧释磷的抑制…