表与表之间关系回顾
1 一对多
(1)分类和商品的关系,一个分类里面有多个商品,一个商品只能属于一个分类。
(2)客户和联系人是一对多关系
客户:与公司有业务往来,百度、新浪、360
联系人:公司里面的员工,百度里面有很多的员工,联系员工
**公司和公司员工的关系
客户是一,联系人是多,
一个客户里面有多个联系人,一个联系人只能属于一个客户
(3)一对多建表:通过外键建立关系
2 多对多
(1)订单和商品关系,一个订单里面有偶多个商品,一个商品属于多个订单
(2)用户和角色多对多关系
用户:小王,小马,小宋
角色:总经理,秘书,司机,保安
**比如小王可以是总经理、四级
**比如小宋可以是四级、秘书、保安
比如小马,可以是秘书、总经理
---一个用户里面可以有多个角色,一个角色可以有多个用户
(3)多对多建表,创建第三张表维护关系
3 一对一
(1)在中国,一个男人只能有一个妻子,一个女人只能有一个丈夫
Hibernate的一对多操作(重点)
一对多映射配置
以客户和联系人为例:客户是一,联系人是多第一步,创建两个实体类,客户和联系人
package cn.itcase.hibernate; import java.util.HashSet; import java.util.Set; public class Customer { private Integer cid; private String custLevel; private String custMoblie; private String custName; private String custPhone; private String custSource; //在客户实体类里面表示多个联系人,一个客户有多个联系人 //hibernate要求使用集合表示多的数据,使用set集合 private Set<LinkMan> setLinkMan=new HashSet<LinkMan>(); public Set<LinkMan> getSetLinkMan() { return setLinkMan; } public void setSetLinkMan(Set<LinkMan> setLinkMan) { this.setLinkMan = setLinkMan; } public Integer getCid() { return cid; } public void setCid(Integer cid) { this.cid = cid; } public String getCustLevel() { return custLevel; } public void setCustLevel(String custLevel) { this.custLevel = custLevel; } public String getCustMoblie() { return custMoblie; } public void setCustMoblie(String custMoblie) { this.custMoblie = custMoblie; } public String getCustName() { return custName; } public void setCustName(String custName) { this.custName = custName; } public String getCustPhone() { return custPhone; } public void setCustPhone(String custPhone) { this.custPhone = custPhone; } public String getCustSource() { return custSource; } public void setCustSource(String custSource) { this.custSource = custSource; } }
package cn.itcase.hibernate; public class LinkMan { private Integer lkm_id; private String lkm_gender; private String lkm_name; private String lkm_phone; //在联系人实体类里面表示所属客户,一个联系人只能属于一个客户 private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } public Integer getLkm_id() { return lkm_id; } public void setLkm_id(Integer lkm_id) { this.lkm_id = lkm_id; } public String getLkm_gender() { return lkm_gender; } public void setLkm_gender(String lkm_gender) { this.lkm_gender = lkm_gender; } public String getLkm_name() { return lkm_name; } public void setLkm_name(String lkm_name) { this.lkm_name = lkm_name; } public String getLkm_phone() { return lkm_phone; } public void setLkm_phone(String lkm_phone) { this.lkm_phone = lkm_phone; } }
第二步,让两个实体类之间相互表示
(1)在客户实体类里面表示多个联系人
一个客户里面有多个联系人
//在客户实体类里面表示多个联系人,一个客户有多个联系人 //hibernate要求使用集合表示多的数据,使用set集合 private Set<LinkMan> setLinkMan=new HashSet<LinkMan>(); public Set<LinkMan> getSetLinkMan() { return setLinkMan; } public void setSetLinkMan(Set<LinkMan> setLinkMan) { this.setLinkMan = setLinkMan; }
(2)在联系人实体类里面表示所属客户
一个联系人只能属于一个客户
第三步,配置映射关系
(1)一般一个实体类对应一个映射文件
(2)把映射最基本配置完成
(3)在配置文件中,配置一对多的关系
在客户映射文件中,表示所有联系人
<!-- 在客户映射文件中,表示所有联系人 使用set标签标识所有的联系人 set标签里面有name属性,属性值卸载客户实体类里面表示联系人的set集合名称 --> <set name="setLinkMan"> <!-- 一对多建表,有外键, hibernate机制,双向维护外键,在一和多那一方面都配置外键 --> <key column = "clid"></key> <!-- 客户所有的联系人,class里面写联系人实体类的全路径 --> <one-to-many class="cn.itcase.hibernate.LinkMan"/> </set>
在联系人映射文件中,表示所属
<!-- 表示联系人所属客户 name属性:因为在联系人实体类使用customer对象表示,写customer名称 column属性:外键名称 --> <many-to-one name="customer" class="cn.itcase.hibernate.Customer" column="clid"></many-to-one>
第四步 创建核心配置文件,把映射文件引入到核心配置文件中
<!-- 第三部分:把映射文件放到核心文件中来 必须的 --> <mapping resource="cn/itcase/hibernate/Customer.hbm.xml"/> <mapping resource="cn/itcase/hibernate/LinkMan.hbm.xml"/>
测试如下:
一对多级联操作
级联操作
1 级联保存
(1)添加一个客户,为这个客户添加多个联系人
2 级联删除
(1)删除一个客户,这个客户里面所有的联系人也删除
一对多级联保存
1 添加客户 ,为这个客户添加一个联系人
@Test public void testAddDemo1() { SessionFactory sessionFactory=HibernateUtils.getSessionFactory(); Session session=sessionFactory.openSession(); Transaction tx=session.beginTransaction(); //添加一个客户,为这个客户添加一个联系人 //1 创建客户和联系人对象 Customer customer=new Customer(); customer.setCustName("创智播客"); customer.setCustLevel("Vip"); customer.setCustSource("网络"); customer.setCustPhone("110"); customer.setCustMoblie("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); //保存到数据库 session.save(customer); session.save(linkman); tx.commit(); session.close(); sessionFactory.close(); }
(2)简化写法
一般根据客户添加联系人
第一步 在客户映射文件在进行配置
在客户映射文件里面set标签进行配置
<set name="setLinkMan" cascade="save-update">第二步 创建客户和联系人对象,只需把联系人放大客户里面就可以了
@Test public void testAddDemo2() { SessionFactory sessionFactory=HibernateUtils.getSessionFactory(); Session session=sessionFactory.openSession(); Transaction tx=session.beginTransaction(); //添加一个客户,为这个客户添加一个联系人 //1 创建客户和联系人对象 Customer customer=new Customer(); customer.setCustName("百度"); customer.setCustLevel("普通客户"); customer.setCustSource("网络"); customer.setCustPhone("110"); customer.setCustMoblie("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(); session.close(); sessionFactory.close(); }2一对多级联删除
1 删除某个客户,把客户里面所有的联系人删除
2 具体实现
第一步 在客户映射文件set标签,进行配置
(1)使用属性cascade属性值delete
<set name="setLinkMan" cascade="save-update,delete">
第二步 在代码中直接删除客户
(1)根据id查询对象,调用session里面的delete方法删除
@Test public void testAddDemo3() { SessionFactory sessionFactory=HibernateUtils.getSessionFactory(); Session session=sessionFactory.openSession(); Transaction tx=session.beginTransaction(); // 1 根据id查询客户对象 Customer customer=session.get(Customer.class, 2); // 2 调用方法进行删除 session.delete(customer); tx.commit(); session.close(); sessionFactory.close(); }
执行过程
(1)根据id查询客户
(2)根据外键id值查询联系人
(3)把联系人外键设置为null
(4)删除联系人和客户
一对多修改操作
1 让lucy联系人所属客户不是传智播客,而是腾讯
@Test public void testUpdate() { SessionFactory sessionFactory=HibernateUtils.getSessionFactory(); Session session=sessionFactory.openSession(); Transaction tx=session.beginTransaction(); //1根据id查询lucy联系人,根据id查询腾讯客户 Customer tengxun=session.get(Customer.class, 3); LinkMan lucy=session.get(LinkMan.class, 1); //2设置持久太对象值 //把联系人放客户里面 tengxun.getSetLinkMan().add(lucy); lucy.setCustomer(tengxun); tx.commit(); session.close(); sessionFactory.close(); }
2 inverse属性
(1)因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候,修改一次外键,修改联系人时候也修改一次外键,造成效率问题。
(2)解决方式:让其中一方不维护外键
一对多里面,让其中一方放弃外键维护,
一个国家有总统,国家有很多人,总统不能认识国家所有人,国家所有人可以认识总统。
(3)具体实现
在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性。
inverse属性值默认false,不放弃关系维护 true表示放弃关系维护 --> <set name="setLinkMan" inverse="true"><!-- cascade="save-update,delete" -->