多表关系
-
一对多
-
多对多
-
一对一
一对多设计
- 创建实体类
- 配置文件
Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- ORM元数据 表对象关系映射文件
package : 配置该配置文件中类所在的包. -->
<hibernate-mapping package="com.lwb.domain">
<class name="com.lwb.domain.Customer" table="t_customer" >
<id name="id" column="id">
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- property : 实体中属性与表中列的对应
name : 实体中属性名称
column : 表中列的名称
length : 数据长度
-->
<property name="name" column="name" type="string"></property>
<!-- 表达一对多的集合 -->
<!-- name:集合的属性名称 -->
<set name="Order">
<!-- key:用来描述外键的
column:外键的值
-->
<key column="cid"></key>
<!-- one-to-many 表达:Customer与Order的关系是一对多
class:表达关联的另一方的完整类名
-->
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- ORM元数据 表对象关系映射文件
package : 配置该配置文件中类所在的包. -->
<hibernate-mapping package="com.lwb.domain">
<class name="com.lwb.domain.Order" table="t_order" >
<id name="id" column="id">
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- property : 实体中属性与表中列的对应
name : 实体中属性名称
column : 表中列的名称
length : 数据长度
-->
<property name="name" column="name" type="string"></property>
<!-- 表达多对一的关系 -->
<!-- name:引用属性名称
column:外键的键名
class:我引用的Customer的完整名称
-->
<many-to-one name="customer" column="cid" class="Customer"></many-to-one>
</class>
</hibernate-mapping>
hibernate.cfg.xml
- 测试案例
Session session = HibernateUtils.openSession();
session.beginTransaction();
//创建对象
Customer c = new Customer();
Order o1 = new Order();
Order o2 = new Order();
c.setName("lwb");
o1.setName("哑铃");
o2.setName("篮球");
//维护关系
c.getOrder().add(o1);
c.getOrder().add(o2);
//保存对象
session.save(c);
session.save(o1);
session.save(o2);
session.getTransaction().commit();
session.clear();
- 优化创建
@Test
//1 测试1对多关系中,保存操作
//共打印5条语句
//前3条打印insert => 保存对象,维护外键
//后两条打印update => 维护外键
//解决=> 单纯指定 关系由其中一方来维护.另一方不维护关系.
//注意=> 外键维护的放弃,只能由非外键所在对象来放弃.
//Customer inverse属性: true
//只打印3条语句=> 外键由order自己来维护
public void test1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//创建对象
Customer c = new Customer();
Order o1 = new Order();
Order o2 = new Order();
c.setName("lwb");
o1.setName("哑铃");
o2.setName("篮球");
//维护关系
//c.getOrder().add(o1);
//c.getOrder().add(o2);
o1.setCustomer(c);
o2.setCustomer(c);
//保存对象
session.save(c);
session.save(o1);
session.save(o2);
session.getTransaction().commit();
session.clear();
}
- 多表删除
- 删除Customer时 ,会先移除 Customer中引用的外键.然后再删除Customer
- 结论: 维护一方的对象时,会自动维护另一方的关系
//多表关系=> 删除
//删除Customer时 ,会先移除 Customer中引用的外键.然后再删除Customer
// 结论: 维护一方的对象时,会自动维护另一方的关系
// Customer 的 inverse属性: true
// 会报错 => Customer不负责维护外键, 直接删除Customer 会导致,order引用了无效的id.违反了外键约束.
@Test
public void fun2(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 3);
// Customer 的 inverse属性: true
Set<Order> set = c.getOrders();
for(Order o : set){
o.setCustomer(null);//设置订单不属于任何Customer
}
session.delete(c);
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 游离状态
}
级联操作
- cascade属性
- save-update:级联保存,级联修改
- delete:删除A,同时删除B,AB都不存在
- delete-orphan:孤儿删除,解除关系,同时将B删除,A存在的。
- 如果需要配置多项,使用逗号分隔。< set cascade=“save-update,delete” >
- all : save-update 和 delete 整合
- all-delete-orphan : 三个整合
- 操作代码:
//测试 一对多关系
public class Demo2 {
@Test
//增
//我们希望在保存Customer时,自动将未保存的Orders当中的Order保存
//cascade: save-update
public void fun1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = new Customer();
c.setName("tom");
Order o1 = new Order();
o1.setName("肥皂");
Order o2 = new Order();
o2.setName("蜡烛");
c.getOrders().add(o1);//维护关系
c.getOrders().add(o2); //维护关系
/*
o1.setCustomer(c);//维护关系
o2.setCustomer(c);//维护关系
*/
session.save(c);//保存对象
//session.save(o1);//保存对象
//session.save(o2);//保存对象
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 游离状态
}
@Test
//增
//我们希望在保存Customer时,自动将未保存的Orders当中的Order保存
//cascade: save-update
public void fun2(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 8);//1条 select
for(Order o :c.getOrders()){ // 1条 select
o.setName("哇哈哈"); // 修改订单
}
//------------------------------------------------
session.getTransaction().commit();//因为设置级联修改,自动将订单的修改保存到数据
//update语句
session.close(); // 游离状态
}
@Test
//cascade: delete
//删除Customer时 ,会将Customer下的订单一并删除
//inverse : false 6条sql语句
//inverse : true 5条sql语句 比上面少一条维护外键
public void fun3(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 7);//1条 select
session.delete(c);//删除Customer
// 删除两个Order
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 游离状态
}
@Test
//cascade: delete
//操作的两方cascade值都为delete
//需要注意: 千万不要在两方都配置 级联删除. 删除任何一方,会导致整个关系链对象全部删除.
public void fun4(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Order o = (Order) session.get(Order.class, 9);//select
session.delete(o);//delete删除当前order
//找到所有关联的Customer删除 select
// delete Customer
// Customer配置了级联删除=> select 找下面的order
// 删除所有Order
//删除Customer
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 游离状态
}
}
@Test
//inverse:false
//cascade: delete-orphan 孤儿删除 => 当没有任何外键引用Order时,order 会被删除
public void fun5(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//------------------------------------------------
Customer c = (Customer) session.get(Customer.class, 9);
Iterator<Order> it = c.getOrders().iterator();
//注意: 删除Customer下的订单时,不能使用 c.setOrders(null); c.setOrders(new HashSet());
while(it.hasNext()){ // 遍历Customer下的订单,并将订单删除 => 维护关系
it.next();
it.remove();
}
//------------------------------------------------
session.getTransaction().commit();
session.close(); // 游离状态
}
多对多设计
-
表关系
-
对象关系
-
配置文件
- 配置多对多关系:
- set:表达集合
- name:集合的属性名
- table:配置多对多中间表的名称
- key:表达外键
- column:表示外键名
- many-to-many:表达多对多关系
- class:集合引用方的类
- column:对方在中间表的外键名
- set:表达集合
- 配置多对多关系:
student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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.lwb.domain">
<class name="com.lwb.domain.Student" table="t_student" >
<id name="id" column="id">
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<!-- 多对多关系 -->
<!-- set:表达集合
name:集合的属性名
key:表达外键
column:表示外键名
many-to-many:表达多对多关系
class:集合引用方的类
column:对方在中间表的外键名
-->
<set name="courses" table="t_student_course">
<key column="sid"></key>
<many-to-many class="Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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.lwb.domain">
<class name="com.lwb.domain.Course" table="t_course" >
<id name="id" column="id">
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<!-- 多对多关系 -->
<!-- set:表达集合
name:集合的属性名
key:表达外键
column:表示外键名
many-to-many:表达多对多关系
class:集合引用方的类
column:对方在中间表的外键名
-->
<set name="students" table="t_student_course">
<key column="cid"></key>
<many-to-many class="Student" column="sid"></many-to-many>
</set>
</class>
</hibernate-mapping>
配置hibernate.cfg.xml
-
测试:
-
多对多操作说明:
- 保存学生:通过学生保存课程,有学生维护外键
- student.hbm.xml配置:
- inverse = false
- cascade = save-update
- course.hbm.xml配置:
- inverse = true
- inverse = true
- student.hbm.xml配置:
- 保存学生:通过学生保存课程,有学生维护外键