Hibernate_day03
上节内容
1 实体类编写规则 2 hibernate主键生成策略 3 实体类操作 (1)crud操作 (2)实体类对象状态 4 hibernate的一级缓存 5 hibernate的事务操作 (1)事务代码规则写法 6 hibernate其他的api(查询) |
今天内容
1 表与表之间关系回顾 (1)一对多(客户和联系人) (2)多对多(用户和角色) 2 hibernate一对多操作 (1)*一对多映射配置 (2)一对多级联保存(同时操作多个表进行保存) (3)一对多级联删除 (4)inverse属性 3 hibernate多对多操作 (1)*多对多映射配置 (2)多对多级联保存(重点) (3)多对多级联删除 (4)维护第三张表 |
表与表之间关系回顾(重点)
1 一对多 (1)分类和商品关系,一个分类里面有多个商品,一个商品只能属于一个分类 (2)客户和联系人是一对多关系 - 客户:与公司有业务往来,百度、新浪、360 - 联系人:公司里面的员工,百度里面有很多员工,联系员工 ** 公司和公司员工的关系 - 客户是一,联系人是多 - 一个客户里面有多个联系人,一个联系人只能属于一个客户 (3)一对多建表:通过外键建立关系 2 多对多 (1)订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单 (2)用户和角色多对多关系 - 用户: 小王、小马、小宋 - 角色:总经理、秘书、司机、保安 ** 比如小王 可以 是总经理,可以是司机 ** 比如小宋 可以是司机,可以是秘书,可以保安 ** 比如小马 可以是 秘书,可以是总经理 - 一个用户里面可以有多个角色,一个角色里面可以有多个用户 (3)多对多建表:创建第三张表维护关系 3 一对一 (1)在中国,一个男人只能有一个妻子,一个女人只能有一个丈夫 |
Hibernate的一对多操作(重点)
一对多映射配置(重点)
以客户和联系人为例:客户是一,联系人是多 第一步 创建两个实体类,客户和联系人 第二步 让两个实体类之间互相表示 (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; } 具体: public class Customer { private Integer cid;// 客户id private String custName;// 客户名称 private String custLevel;// 客户级别 private String custSource;// 客户来源 private String custPhone;// 联系电话 private String custMobile;// 手机 // 在客户实体类里面表示多个联系人,一个客户有多个联系人 // 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 getCustName() { return custName; } public void setCustName(String custName) { this.custName = custName; } public String getCustLevel() { return custLevel; } public void setCustLevel(String custLevel) { this.custLevel = custLevel; } public String getCustSource() { return custSource; } public void setCustSource(String custSource) { this.custSource = custSource; } public String getCustPhone() { return custPhone; } public void setCustPhone(String custPhone) { this.custPhone = custPhone; } public String getCustMobile() { return custMobile; } public void setCustMobile(String custMobile) { this.custMobile = custMobile; } } (2)在联系人实体类里面表示所属客户 - 一个联系人只能属于一个客户 //在联系人实体类里面表示所属客户,一个联系人只能属于一个客户 private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } 具体: public class LinkMan { private Integer lkm_id; // 联系人编号(主键) private String lkm_name;// 联系人姓名 private String lkm_gender;// 联系人性别 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_name() { return lkm_name; } public void setLkm_name(String lkm_name) { this.lkm_name = lkm_name; } public String getLkm_gender() { return lkm_gender; } public void setLkm_gender(String lkm_gender) { this.lkm_gender = lkm_gender; } public String getLkm_phone() { return lkm_phone; } public void setLkm_phone(String lkm_phone) { this.lkm_phone = lkm_phone; } }
(1)一般一个实体类对应一个映射文件 (2)把映射最基本配置完成 Customer.hbm.xml <!-- 1 配置类和表对应 class标签 name属性:实体类全路径 table属性:数据库表名称 --> <class name="cn.itcast.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> LinkMan.hbm.xml <!-- 1 配置类和表对应 class标签 name属性:实体类全路径 table属性:数据库表名称 --> <class name="cn.itcast.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> (3)在映射文件中,配置一对多关系 - 在客户映射文件中,表示所有联系人 Customer.hbm.xml <!-- 在客户映射文件中,表示所有联系人 使用set标签表示所有联系人 --> <set name="setLinkMan"> <!-- 一对多建表,有外键 hibernate机制,双向维护外键,在一和多那一方都配置外键 column属性值,外键名称 --> <key column="clid"></key> <!-- 客户所有的联系人,class里面写联系人的实体类全路径 --> <one-to-many class="cn.itcast.entity.LinkMan" /> </set> - 在联系人映射文件中,表示所属客户 LinkMan.hbm.xml <!-- 表示联系人所属客户 name属性:因为在联系人实体类使用customer对象表示,写customer名称 class属性:customer全路径 column属性:外键名称 --> <many-to-one name="customer" class="cn.itcast.entity.Customer"column="clid"></many-to-one> 第四步 创建核心配置文件,把映射文件引入到核心配置文件中
测试: 运行HibernateUtils.java工具类 public class HibernateUtils { static Configuration cfg = null; static SessionFactory sessionFactory = null; //静态代码块实现 static { //加载核心配置文件 cfg = new Configuration().configure(); sessionFactory = cfg.buildSessionFactory(); } //提供返回与本地线程绑定的session方法 public static Session getSessionObject() { return sessionFactory.getCurrentSession(); } // 提供方法返回sessionFactory public static SessionFactory getSessionFactory() { return sessionFactory; } public static void main(String[] args) { } } |
一对多级联操作
级联操作 1 级联保存 (1)添加一个客户,为这个客户添加多个联系人 2 级联删除 (1)删除某一个客户,这个客户里面的所有的联系人也删除 |
一对多级联保存
1 添加客户,为这个客户添加一个联系人 (1)复杂写法: public class HibernateOnetoMany { //演示一对多级联保存 复杂写法 @Test public void testAddDemo1() { SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try{ sessionFactory = HibernateUtils.getSessionFactory(); //与本地线程绑定的session session = sessionFactory.openSession(); //开启事务 tx = session.beginTransaction(); //添加一个客户,为这个客户添加一个联系人 //1.创建客户和联系人对象 Customer customer = new Customer(); customer.setCustName("小李"); customer.setCustLevel("vip"); customer.setCustSource("网络"); customer.setCustPhone("999"); customer.setCustMobile("666"); LinkMan linkman = new LinkMan(); linkman.setLkm_name("小容"); linkman.setLkm_gender("女"); linkman.setLkm_phone("520"); //2 在客户表示所有联系人,在联系人表示客户 // 建立客户对象和联系人对象关系 //2.1 把联系人对象 放到客户对象的set集合里面 customer.getSetLinkMan().add(linkman); //2.2把客户对象放到联系人里面 linkman.setCustomer(customer); //3 保存到数据库 session.save(customer); session.save(linkman); //提交事务 tx.commit(); }catch(Exception e) { e.printStackTrace(); //回滚事务 tx.rollback(); }finally { //关闭操作 session.close(); sessionFactory.close(); } } } (2)简化写法 - 一般根据客户添加联系人 第一步 在客户映射文件中进行配置 - 在客户映射文件里面set标签进行配置
第二步 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户就可以了 //演示一对多级联保存 简单写法 @Test public void testAddDemo2() { SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try{ sessionFactory = HibernateUtils.getSessionFactory(); //与本地线程绑定的session session = sessionFactory.openSession(); //开启事务 tx = session.beginTransaction(); //添加一个客户,为这个客户添加一个联系人 //1.创建客户和联系人对象 Customer customer = new Customer(); customer.setCustName("百度"); customer.setCustLevel("普通客户"); customer.setCustSource("网络"); customer.setCustPhone("999"); customer.setCustMobile("777"); LinkMan linkman = new LinkMan(); linkman.setLkm_name("小宏"); linkman.setLkm_gender("男"); linkman.setLkm_phone("555"); //2 把联系人对象 放到客户对象的set集合里面 customer.getSetLinkMan().add(linkman); //3 保存客户 session.save(customer); //提交事务 tx.commit(); }catch(Exception e) { e.printStackTrace(); //回滚事务 tx.rollback(); }finally { //关闭操作 session.close(); sessionFactory.close(); } } |
一对多级联删除
1 删除某个客户,把客户里面所有的联系人删除 2 具体实现 第一步 在客户映射文件set标签,进行配置 (1)使用属性cascade属性值 delete 第二步 在代码中直接删除客户 (1)根据id查询对象,调用session里面delete方法删除
3 执行过程: (1)根据id查询客户 (2)根据外键id值查询联系人
(3)把联系人外键设置为null (4)删除联系人和客户 |
一对多修改操作(inverse属性)
1 让小容联系人所属客户不是小李,而是小王 //1 根据id查询小容联系人,根据id查询小王的客户 Customer customer = session.get(Customer.class, 2); LinkMan linkman = session.get(LinkMan.class, 1); //2 设置持久态对象值 //把联系人(小容)放到客户(小王)里面 customer.getSetLinkMan().add(linkman); //把客户(小王)放到联系人(小容)里面 linkMan.setCustomer(customer); 2 inverse属性 (1)因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题
(2)解决方式:让其中的一方不维护外键 - 一对多里面,让其中一方放弃外键维护 - 一个国家有总统,国家有很多人,总统不能认识国家所有人,国家所有人可以认识总统 (3)具体实现: 在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性 |