Hibernate 中一对多和多对多映射

1. 一对多映射

1.1 JavaWeb 一对多建表原则

  • 多方表的外键指向一方表的主键;

1.2 编写一对多的 JavaBean

// 客户(一方)和联系人(多方)
    // 客户(一方) JavaBean
    public class Customer{ private Long cust_id; private String cust_name; private Long cust_create_id; ... // 关联多方 // Hibernate 框架默认的集合是 Set 集合,该集合必须要自己手动初始化 private Set<Linkman> linkmans = new HashSet<Linkman>(); ...... } // 联系人(多方) JavaBean public class Linkman{ private Long lkm_id; private String lkm_name; private String lkm_gender; ... // 关联一方 // 编写一个对象, 不需要自己 new private Customer customer; .... }

1.3 编写一对多的映射配置文件

// Customer.hbm.xml (客户映射配置)
    <class name="com.itheima.domain.Customer" table="cst_customer"> <id name="cust_id" column="cust_id"> <generator class="native"/> </id> <property name="cust_name" column="cust_name"/> <property name="cust_create_id" column="cust_create_id"/> ... // 关联的配置(一方) // name 表示集合的名称 <set name="linkmans"> <key column="lkm_cust_id"/> // column 外键的字段 <one-to-many class="com.itheima.domain.Linkman"/> </set> </class> // Linkman.hbm.xml (联系人映射配置) <class name="com.itheima.doamin.Linkman" table="cst_linkman"> <id name="lkm_id" column="lkm_id"> <generator class="native"/> </id> <property name="lkm_name" column="lkm_name"/> <property name="lkm_gender" column="lkm_gender"/> ... // 关联的配置(多方) // name 当前 JavaBean 中的属性 // class 属性的全路径 // column 外键的字段(表) <many-to-one name="customer" class="com.itheima.domain.Customer" column="lkm_cust_id"/> </class>

2. 保存客户和联系人的数据

2.1 双向关联的方式保存数据

 public class Demo{
    public void fun(){ Session session = HibernateUtils.getCurrentSession(); Transaction tr = session.beginTransaction(); // 创建客户 Customer c1 = new Customer(); c1.setCust_name("张三"); // 创建联系人 Linkman lk1 = new Linkman(); lk1.setLkm_name("熊大"); Linkman lk2 = new Linkman(); lk2.setLkm_name("熊二"); // 双向关联 c1.getLinkmans().add(lk1); c1.getLinkmans().add(lk2); lk1.setCustomer(c1); lk2.setCustomer(c1); session.save(c1); session.save(lk1); session.save(lk2); tr.commit(); } }

2.2 级联保存

  • 级联保存:保存一方,同时可以把关联的对象也保存到数据库中!
  • 级联保存是有方向性的.例如,保存客户时,级联保存联系人;或者,保存联系人时,级联保存客户;
  • 使用 cascade="save-update"
// 保存客户,级联保存联系人
    // 需要在客户 Customer.hbm.xml 中配置
    <set name="linkmans" cascade="save-update"> <key column="lkm_cust_id"/> <one-to-many class="com.itheima.domain.Linkman"/> </set> pulic class Demo{ pulic class fun(){ Session session = HibernateUtils.getCurrentSession(); Transaction tr = session.beginTransaction(); // 创建客户 Customer c1 = new Customer(); c1.setCust_name("张三"); // 创建联系人 Linkman l1 = new Linkman(); l1.setLkm_name("熊大"); Linkman l2 = new Linkman(); l2.setLkm_name("熊二"); // 单向关联 c1.getLinkmans().add(l1); c1.getLinkmans().add(l2); l1.setCustomer(c1); // 此处,如果没有,报错. l2.setCustomer(c1); // 此处,如果没有,报错. // 保存客户 session.save(c1); tr.commit(); } } // 保存联系人,级联保存客户 // 需要在联系人 Linkman.hbm.xml 中配置 <many-to-one name="customer" class="cn.itheima.domain.Customer" column="lkm_cust_id" cascade="save-update"/> public class Demo{ public class fun(){ Session session = HibernateUtils.getCurrentSession(); Transaction tr = session.beginTransaction(); // 创建客户 Customer c1 = new Customer(); c1.setCust_name("张三"); // 创建联系人 Linkman l1 = new Linkman(); l1.setLkm_name("熊大"); Linkman l2 = new Linkman(); l2.setLkm_name("熊二"); l1.setCustomer(c1); l2.setCustomer(c2); // 保存联系人 session.save(l1); session.save(l2); tr.commit(); } }

2.3 级联删除

  • 级联删除也是有方向性的;
// 删除客户时, 删除联系人(一方级联删除多方), 配置 Customer.hbm.xml
    <set name="linkmans" cascade="delete">
        <key column="lkm_cust_id"/> <one-to-many class="cn.itheima.domain.Linkman"/> </set>

2.4 级联的取值和孤儿删除

1. 级联的取值(cascade 的取值)
  • none: 不使用级联;
  • save-update: 级联保存或更新;
  • delete: 级联删除;
  • delete-orphan: 孤儿删除(只能应用在一对多关系);
  • all: 除了 delete-orphan 的所有情况;
  • all-delete-orphan: 包含了 delete-orphan 的所有情况;
2. 孤儿删除
  • 只有在一对多的环境下才有孤儿删除;
  • 在一对多的关系中,可以将一方认为是父方,将多的一方认为是子方;孤儿删除,就是在解除了父子关系的时候,
    将子方记录直接删除;

2.5 让某一方放弃外键的维护,为多对多映射做准备: inverse

  1. 在修改客户和联系人的关系时,进行双向关联,双方都会维护外键,会产生多余的 SQL 语句.
    • 产生的原因: session 的一级缓存中的快照机制,会让双方都更新数据库,产生了多余的 SQL 语句.
  2. 如果不想产生多余的 SQL 语句,那么需要一方来放弃外键的维护, 由多方来维护!
// 放弃外键维护
    // Customer.hbm.xml 进行如下配置
    <set name="linkman" inverse="true"> // true 表示放弃; 默认值为 false <key column="lkm_cust_id"/> <one-to-many class="com.itheima.domain.Linkman"/> </set>

3. 多对多映射

3.1 多对多建表原则

  • 以用户和角色为例,需要创建三张表: 用户表,角色表,中间表(维护前面两个表的数据);
  • 使用Hibernate 框架,只要编写两个 JavaBean 以及对应的映射配置文件,中间表会自动生成;
  • 多对多映射关系中,必须有一方放弃外键维护;

// 编写用户和角色的 JavaBean
    // 用户的 JavaBean
    public class User{ private Long user_id; private String user_name; private String user_pwd; ... private Set<Role> roles = new HashSet<Role>(); } // 角色的 JavaBean public class Role{ private Long role_id; private String role_name; private String role_desc; private Set<User> users = new HashSet<User>(); } // 编写映射配置文件 // 用户的映射配置文件, User.hbm.xml <class name="com.itheima.domain.User" table="sys_user"> <id name="user_id" column="user_id"> <generator class="native"/> </id> <property name="user_name" column="user_name"/> <property name="user_pwd" column="user_pwd"/> // 配置多对多 // name 表示集合的名称 // table 表示中间表的名称 <set name="roles" table="sys_user_role" inverse="true"> // 当前对象在中间表的外键名称 <key column="user_id"/> // class : 集合中存入的对象,对象的全路径 // column: 集合中对象,在中间表的外键名称 <many-to-many class="com.itheima.domain.Role" column="role_id"/> </set> </class> // 角色的映射配置文件, Role.hbm.xml <class name="com.itheima.domain.Role" table="sys_role"> <id name="role_id" column="role_id"> <generator class="native"/> </id> <property name="role_name" column="role_name"/> <property name="role_desc" column="role_desc"/> <set name="users" table="sys_user_role"> <key column="role_id"/> <many-to-many class="com.itheima.domain.User" column="user_id"/> </set> </class> 

猜你喜欢

转载自www.cnblogs.com/Jeely/p/11226422.html