一.表与表之间关系回顾
1.一对多
- 分类和商品的关系,一个分类里面有多个商品,一个商品只能属于一个分类
- 客户和联系人是一对多关系
- 客户:与公司有业务往来,百度,新浪,360
- 联系人:公司里面的员工,百度里面有很多员工,联系员工
- 公司和公司员工的关系
- 客户是一,联系人是多
- 一个客户里面有多个联系人,一个联系人只能属于一个客户
- 一对多建表,通过外键建立关系
2.多对多
- 订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单
- 用户和角色多对多关系
- 用户:小王,小马,小宋
- 角色:总经理,秘书,司机,保安
- 比如小王 可以 是总经理,可以是司机
- 比如小宋 可以 是司机,可以是秘书,可以是保安
- 比如小马 可以 是秘书,可以是总经理
- 一个用户里面可以由多个角色,一个角色里面可以有多个用户
- 多对多建表,创建第三张表维护关系
3.一对一
- 在中国,一个男人只能有一个妻子,一个女人只能有一个丈夫
二.Hibernate的一对多操作
1.一对多映射配置
- 导入hibernate jar包
- 以客户和联系人为例:客户是一,联系人是多
(1).创建两个实体类,客户和联系人
(2).让两个实体类之间互相表示
- 在客户实体类里面表示多个联系人
- 一个客户里面有多个联系人
- 在联系人实体类里面表示所属客户
- 一个联系人只能属于一个客户
(3).配置映射关系
- 一般一个实体类对应一个映射文件
- 把映射最基本配置完成
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">
<hibernate-mapping>
<class name="cn.st.web.entity.LinkMan" table="t_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
</class>
</hibernate-mapping>
LinkMan.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>
<class name="cn.st.web.entity.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="custName" column="custName"></property>
<property name="custLevel" column="custLevel"></property>
<property name="custSource" column="custSource"></property>
<property name="custPhone" column="custPhone"></property>
<property name="custMobile" column="custMobile"></property>
</class>
</hibernate-mapping>
- 在映射文件中,配置一对多关系
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">
<hibernate-mapping>
<class name="cn.st.web.entity.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="custName" column="custName"></property>
<property name="custLevel" column="custLevel"></property>
<property name="custSource" column="custSource"></property>
<property name="custPhone" column="custPhone"></property>
<property name="custMobile" column="custMobile"></property>
<!-- 在客户映射文件中,表示所有联系人,使用set标签表示所有联系人
set标签里面有name属性:属性值写在客户实体类里面表示联系人的set集合
-->
<set name="setLinkMan">
<!-- 一对多建表,有外键
hibernate机制:双向维护外键,在一和多那一方都配置外键
column属性值:外键名称
-->
<key column="clid"></key>
<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
<one-to-many class="cn.st.web.entity.LinkMan"/>
</set>
</class>
</hibernate-mapping>
LinkMan.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>
<class name="cn.st.web.entity.LinkMan" table="t_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<!-- 表示联系人所属客户
name属性:因为在联系人实体类使用Customer对象表示,写customer名称
class属性:customer全路径
column属性:外键名称
-->
<many-to-one name="customer" class="cn.st.web.entity.Customer" column="clid" ></many-to-one>
</class>
</hibernate-mapping>
(4).创建核心配置文件,把映射文件引入到核心配置文件
<mapping resource="cn/st/web/entity/Customer.hbm.xml"/>
<mapping resource="cn/st/web/entity/LinkMan.hbm.xml"/>
2.测试
三.一对多级联操作
1.级联保存
(1).一对多级联保存复杂写法
public void testAdd() {
Session session=null;
Transaction tx=null;
try {
session=hibernateUtils.getSessionobject();
tx=session.beginTransaction();
//添加一个客户,为这个客户添加一个联系人
//1.创建客户和联系人对象
Customer customer=new Customer();
customer.setCustName("传智播客");
customer.setCustLevel("vip");
customer.setCustSource("网络");
customer.setCustPhone("110");
customer.setCustMobile("999");
LinkMan linkMan=new LinkMan();
linkMan.setLkm_name("lucy");
linkMan.setLkm_gender("男");
linkMan.setLkm_phone("911");
//2 在客户表示所有联系人,在联系人表示客户
//建立客户对象和联系人对象关系
//2.1 把联系人对象 放到客户实体类对象的set集合里面
customer.getSetLinkMan().add(linkMan);
//2.2 把客户对象放到联系人里面
linkMan.setCustomer(customer);
//3.保存到数据库
session.save(customer);
session.save(linkMan);
tx.commit();//3.提交事务
}catch(Exception e){
e.printStackTrace();
tx.rollback();//回滚事务
}finally {
if(session!=null)
session.close();
}
}
(2).简化写法
- 一般根据客户添加联系人
- 第一步 在客户映射文件中进行配置
- 在客户映射文件里面set标签进行配置
- 在客户映射文件里面set标签进行配置
- 第二步 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存一个客户就可以了
public void testAdd2() {
Session session=null;
Transaction tx=null;
try {
session=hibernateUtils.getSessionobject();
tx=session.beginTransaction();
//1.创建客户和联系人对象
Customer customer=new Customer();
customer.setCustName("百度");
customer.setCustLevel("普通客户");
customer.setCustSource("网络");
customer.setCustPhone("110");
customer.setCustMobile("999");
LinkMan linkMan=new LinkMan();
linkMan.setLkm_name("小航");
linkMan.setLkm_gender("男");
linkMan.setLkm_phone("911");
//2.把联系人放到客户里面
customer.getSetLinkMan().add(linkMan);
//3.保存客户
session.save(customer);
tx.commit();//3.提交事务
}catch(Exception e){
e.printStackTrace();
tx.rollback();//回滚事务
}finally {
if(session!=null)
session.close();
}
}
2.级联删除
- 删除某个客户,把客户里面所有的联系人删除
具体实现
- 第一步 在客户映射文件set标签,进行配置
- (1).使用属性cascade属性值 delete
第二步 在代码中直接删除客户
- (1).根据id查询对象,调用session里面delete方法删除
- (1).根据id查询对象,调用session里面delete方法删除
执行过程
- (1).根据id查询客户
- (2).根据外键查联系人
- (3).把联系人外键设置为null
- (4).删除联系人和客户
- (1).根据id查询客户
public void testDelete() {
Session session=null;
Transaction tx=null;
try {
session=hibernateUtils.getSessionobject();
tx=session.beginTransaction();
Customer customer=session.get(Customer.class,1);
session.delete(customer);
tx.commit();//3.提交事务
}catch(Exception e){
e.printStackTrace();
tx.rollback();//回滚事务
}finally {
if(session!=null)
session.close();
}
}
3.级联修改(inverse属性值)
- 让lucy联系人所属联系人不是传智播客,而是百度
“`
public void testUpdate() {
Session session=null;
Transaction tx=null;
try {
session=hibernateUtils.getSessionobject();
tx=session.beginTransaction();
//根据id查询lucy联系人,根据id查询百度的客户
Customer baidu=session.get(Customer.class,3);
LinkMan lucy=session.get(LinkMan.class,3);
//2.设置持久态对象值
//把联系人放到客户里面
baidu.getSetLinkMan().add(lucy);
//把客户放到联系人里面
lucy.setCustomer(baidu);
//持久态会自动更新数据库
tx.commit();
}catch(Exception e){
e.printStackTrace();
tx.rollback();//回滚事务
}finally {
if(session!=null)
session.close();
}
}
- inverse属性
- (1).因为Hibernate是双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题
- (2).解决方式:让其中的一方不维护外键
- 一对多里面,让其中一方放弃外键维护
- 一个国家有总统,国家有很多人,总统不能认识国家所有人,国家所有人可以认识总统
- (1).因为Hibernate是双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题
- (3).具体实现
- 在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
之后就只修改一次了
- 在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
END!!!!!