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(); } // 补全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(); } |
查询结果:
一对多关联查询成功!!!
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; @OneToOne //2.必须要指定关联的外键 @JoinColumn(name="stu_id") private Student student; 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(); } |
测试结果:
多对多配置成功!!!