需求:项目 和 开发人员;
一个项目可以有多个开发人员,一个开发人员也可以参加多个项目,这种映射关系叫做 多对多映射。
项目结构:
项目实体类 Project.java:
package com.hibernate.many2many;
import java.util.Set;
/**
* 项目实体类
*/
public class Project {
private int pro_id;
private String pro_name;
private Set<Developer> developers; // 一个项目可以对应多个开发人员
public int getPro_id() {
return pro_id;
}
public void setPro_id(int pro_id) {
this.pro_id = pro_id;
}
public String getPro_name() {
return pro_name;
}
public void setPro_name(String pro_name) {
this.pro_name = pro_name;
}
public Set<Developer> getDevelopers() {
return developers;
}
public void setDevelopers(Set<Developer> developers) {
this.developers = developers;
}
}
开发者实体类 Developer.java:
package com.hibernate.many2many;
import java.util.Set;
/**
* 开发者实体类
*/
public class Developer {
private int dev_id;
private String dev_name;
private Set<Project> projects; // 一个开发人员可以对应多个项目
public int getDev_id() {
return dev_id;
}
public void setDev_id(int dev_id) {
this.dev_id = dev_id;
}
public String getDev_name() {
return dev_name;
}
public void setDev_name(String dev_name) {
this.dev_name = dev_name;
}
public Set<Project> getProjects() {
return projects;
}
public void setProjects(Set<Project> projects) {
this.projects = projects;
}
}
项目配置文件 Project.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 项目配置文件 -->
<hibernate-mapping package="com.hibernate.many2many">
<class name="Project" table="t_project">
<!-- 主键映射 -->
<id name="pro_id" column="pro_id">
<generator class="native"/>
</id>
<!-- 普通字段映射 -->
<property name="pro_name"/>
<!--
多对多映射:
name="developers":指定映射的集合属性;
table="t_relation":集合属性对应的中间表;
column="pro_id":当前对象在 中间表中的 外键字段;
class="Developer":集合属性 元素的类型(开发者对象);
column="dev_id":当前对象在 中间表中 对应 开发者对象的 外键字段;
cascade:级联操作
none:默认值,表示不级联操作;
save-update:表示级联保存和修改,即保存和修改项目表中的数据时,会自动保存和修改相关联的 开发者表中的数据;
delete:级联删除,当删除项目表中的数据时,会自动删除相关联的开发者表中的数据;
all:所有操作都级联
-->
<set name="developers" table="t_relation" cascade="save-update">
<key column="pro_id"/>
<many-to-many class="Developer" column="dev_id"/>
</set>
</class>
</hibernate-mapping>
开发者配置文件 Developer.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 开发者配置文件 -->
<hibernate-mapping package="com.hibernate.many2many">
<class name="Developer" table="t_developer">
<!-- 主键映射 -->
<id name="dev_id" column="dev_id">
<generator class="native"/>
</id>
<!-- 普通字段映射 -->
<property name="dev_name"/>
<!--
多对多映射:
name="projects":指定映射的集合属性
table="t_relation":集合属性对应的中间表
column="dev_id":当前对象在 中间表中的 外键字段
class="Project":集合属性 元素的类型(项目对象)
column="pro_id":当前对象在 中间表中 对应的 项目对象的 外键字段
-->
<set name="projects" table="t_relation">
<key column="dev_id"/>
<many-to-many class="Project" column="pro_id"/>
</set>
</class>
</hibernate-mapping>
主配置文件 hibernate.cfg.xml:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hib_demo</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 显示 sql 语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 如果表不存在,则自动建表;如果表已存在,则更新表; -->
<property name="hibernate.hbm2ddl.auto">update</property>
</session-factory>
</hibernate-configuration>
测试程序 Demo.java:
package com.hibernate.many2many;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
public class Demo {
private static SessionFactory sessionFactory;
static {
// 加载主配置文件,自动加载映射文件,创建 session 工厂
sessionFactory = new Configuration()
.configure()
.addClass(Developer.class)
.addClass(Project.class)
.buildSessionFactory();
}
@Test
public void test1(){
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
// 创建项目对象
Project project1 = new Project();
project1.setPro_name("电商系统");
Project project2 = new Project();
project2.setPro_name("OA系统");
// 创建开发者对象
Developer developer1 = new Developer();
developer1.setDev_name("张三");
Developer developer2 = new Developer();
developer2.setDev_name("李四");
Developer developer3 = new Developer();
developer3.setDev_name("王五");
// 假设 张三、李四 参加了 电商系统,那么将 张三、李四 添加到一个 set 集合中
Set<Developer> developers1 = new HashSet<>();
developers1.add(developer1);
developers1.add(developer2);
// 假设 李四、王五 参加了 OA 系统,那么将 李四、王五 添加到一个 set 集合中
Set<Developer> developers2 = new HashSet<>();
developers2.add(developer2);
developers2.add(developer3);
// 关联关系:通过项目对象 维护开发者对象
project1.setDevelopers(developers1); // 电商系统维护的开发人员为 张三和李四
project2.setDevelopers(developers2); // OA 系统维护的开发人员为 李四和王五
// 保存:因为 项目配置文件(Project.hbm.xml) 中配置了 级联保存和修改,
// 所以保存 项目数据时,会自动保存 相关联的开发者数据
session.save(project1);
session.save(project2);
transaction.commit();
session.close();
}
}
结果:
inverse 控制反转对 多对多维护关联关系的影响:
1、保存数据:
有影响;
inverse = "false",有控制权,可以维护关联关系:保存数据的时候会把对象关系插入中间表;
inverse = "true",没有控制权,不能维护关联关系:即不会往中间表插入数据;
2、获取数据:
没有影响;
3、解除关联关系:
有影响;
inverse = "false",有控制权,解决关系就是删除中间表的数据;
inverse = "true",没有控制权,不能解除关系;
4、删除数据:
有影响;
inverse = "false",有控制权,先删除中间表数据,在删除自身;
inverse = "true",没有控制权,如果删除的数据有被外键引用,会报错;