多表关系映射


1、一对一(会用即可)

主表:没有外键 有主键

从表:拥有外键的是从表

先操作从表,再去操作主表

one-to-one  ,many-to-one 只是表达多个表之间的关系。

外键:目的是多表连接
主键:目的是唯一标识数据

示例: 一个人对应一个身份证 ,一夫一妻制, 一个萝卜一个坑。。。。

一对一的关系用程序如何描述:

示例:一夫一妻制

Husband.java

 
 
 
public class Husband{
   private Integer marryId; //结婚编号
   private String name; //名称
   private Integer age; //年龄
   private  Integer  hid; //丈夫的身份证号   
   private  Wife wife; //丈夫和妻子有一对一的关系 
   set/get....
}

Wife.java

 
 
 
public class Wife{
   private Integer marryId; //妻子的身份证号
   private String name; //名称
   private Integer age; //年龄
   private  Integer  wid; //结婚编号  
   private   Husband  husband;//妻子和丈夫有一对一的关系
   set/get....
}

1.1 方式一: 按照主键映射 (主键都是一样的)

用已有的主键充当外键去连接表来表示关系

元数据配置文件:

1.1.1 Husband.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.qf.domain">
    <class name="Husband" table="husband">
        <id name="marryId">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="age"></property>
        <property name="hid"></property>
      <!-- 表达的是一对一的关系   constrained="true"表示外键约束-->
      <one-to-one name="wife" constrained="true"></one-to-one>
    </class>
</hibernate-mapping>
1.1.2 Wife.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.qf.domain">
    <class name="Wife" table="wife">
        <id name="marryId">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="age"></property>
        <property name="wid"></property>
      <!-- 表达一对一的关系:
          当前Wife和name变量代指的类映射的表建立一对一的关系。 -->
       <one-to-one name="husband"></one-to-one>
    </class>
</hibernate-mapping>
1.1.3 测试
 
 
 
/**
 * one-to-one表示一对一的关系。  
 * constrained="true"表示外键约束。当前类映射表的主键作为外键去连接另外一个表的主键。
 * 示例: husband的主键作为外键去连接wife的主键。建立了一对一的关系(夫妻关系)。
 * 
 * 主表 wife
 * 副表(从表) husband  维护外键,通过外键去连接主表的主键
 * 
 * 手动删除表的先删除副表。再删除主表。
 * 
 * 方式一: 按照主键关系映射的(用已有的主键充当外键去连接关系) 上午重点:
 * 方式二:按照外键关系映射的。(给表插入额外的一个列作为外键去连接另外一个表) 
 */
@Test
    public void test01() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        try {
            Husband husband =new Husband();
            husband.setName("丈夫");
            
            Wife wife =new Wife();
            wife.setName("妻子");
            
            //表达一对一的关系
            husband.setWife(wife);          
            wife.setHusband(husband);
            
            
            //有约束关系的表后插入(该表插入的时候要 找对应的关系的那条数据)
            //先插入主表
            session.save(wife);
            //后插入副表
            session.save(husband);  
            transaction.commit();
        } catch (Exception e) {
            // TODO: handle exception
            if (transaction!=null) {
                transaction.rollback();
            }
        }
    }

1.2 按照外键映射

给表额外插入一个列作为外键去连接另一个表

java持久化类

 
 
 
Wife.java
public class Wife{
   private Integer wid; //妻子的身份证号(主键)
   private String name; //名称
   private Integer age; //年龄
   private  Integer  marryId; //结婚编号  
   private   Husband  husband;//妻子和丈夫有一对一的关系
   set/get.... 
}
Husband.java
public class Husband{
   private Integer hid; //丈夫的身份证号 (主键) 
   private String name; //名称
   private Integer age; //年龄
   private  Integer  marryId; //结婚编号
   private  Wife wife; //丈夫和妻子有一对一的关系 
   set/get....
   
   //理解:  多个表中主键都有各自的含义及内容的时候(主键不一样)
   //给husband额外插入一个列wife_id1,作为外键去连接wife表
}

1.2.1 Husband.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.qf.domain">
    <class name="Husband" table="husband">
        <id name="hid">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="age"></property>
        <property name="marryId"></property>
      <!-- 目的: 表达的是一对一的关系   
          many-to-one原本:多对一,使用unique="true"属性进行转化变成一对一
          column:声明一个外键,去连接另一个表  (值随意定义,见名之意)
          -->
      <many-to-one name="wife" unique="true" column="wife_id1"></many-to-one>  
    </class>
</hibernate-mapping>
1.2.2 Wife.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.qf.domain">
    <class name="Wife" table="wife">
        <id name="wid">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="age"></property>
        <property name="marryId"></property>
      <!-- 表达一对一的关系:
          当前Wife和name变量代指的类映射的表建立一对一的关系。 -->
       <one-to-one name="husband"></one-to-one>
    </class>
</hibernate-mapping>
1.2.3 测试
 
 
 
@Test
    public void test01() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        try {
           Husband husband =new Husband();
            husband.setName("丈夫1");
            
            Wife wife =new Wife();
            wife.setName("妻子1");
            
            //表达一对一的关系
            husband.setWife(wife);          
            wife.setHusband(husband);
            
            
            //有约束关系的表后插入(该表插入的时候要 找对应的关系的那条数据)
            //先插入主表
            session.save(wife);
            //后插入副表
            session.save(husband);
            
            transaction.commit();
        } catch (Exception e) {
            // TODO: handle exception
            if (transaction!=null) {
                transaction.rollback();
            }
        }
    }
    

2、一对多|多对一(最常见的,重点掌握)

示例:客户和联系人为例:

一对多: 一个客户对应多个联系人

多对一:多个联系人对应一个客户

2.1 持久化类
 
 
 
package com.qf.domain;
//从表(拥有外键。)
public class Contact {
private Integer contact_id; //主键
private String contact_name;
private Integer contact_cust_id;//外键(表达关系的时候声明外键即可)
private String contact_gender;
private String contact_phone;
private String contact_mobile;
private String contact_email;
private String contact_qq;
private String contact_position;
private String contact_memo;//备注
//表达多(Contact)对一(Customer)关系
private Customer customer;
set/get.....
}
 
 
 
package com.qf.domain;
import java.util.HashSet;
import java.util.Set;
//主表
public class Customer {
    private Integer  cust_id;//主键
    private String  cust_name;
    private Integer  cust_user_id;
    private Integer  cust_create_id;
    private String  cust_source;
    private String  cust_industry;
    private String  cust_level;
    private String  cust_linkman;
    private String  cust_phone;
    private String  cust_mobile;
    
    //表达一(Customer)对多(Contact)的关系
    private Set<Contact> contacts =new HashSet<>();
    set/get.....
}
2.2 映射文件
Contact.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.qf.domain">
    <class name="Contact" table="contact">
        <id name="contact_id">
            <generator class="native"></generator>
        </id>
        <property name="contact_name" ></property>
        <property name="contact_gender" ></property>
        <property name="contact_phone" ></property>
        <property name="contact_mobile" ></property>
        <property name="contact_email" ></property>
        <property name="contact_qq" ></property>
        <property name="contact_position" ></property>
        <property name="contact_memo" ></property>
        
        <!-- 表达多对一关系
         column:声明外键-->
        <many-to-one name="customer" column="contact_cust_id"></many-to-one>    
    </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 package="com.qf.domain">
    <class name="Customer" table="customer">
        <id name="cust_id" column="cust_id">
            <generator class="native"></generator>
        </id>
        <property name="cust_name" column="cust_name"></property>
        <property name="cust_user_id" column="cust_user_id"></property>
        <property name="cust_create_id" column="cust_create_id"></property>
        <property name="cust_source" column="cust_source"></property>
        <property name="cust_industry" column="cust_industry"></property>
        <property name="cust_level" column="cust_level"></property>
        <property name="cust_linkman" column="cust_linkman"></property>
        <property name="cust_phone" column="cust_phone"></property>
        <property name="cust_mobile" column="cust_mobile"></property>   
        <!-- 表达一对多的关系 -->
         <set name="contacts">
            <!-- column外键:说明哪一个外键要连接当前的表 -->
           <key column="contact_cust_id"></key>
           <!-- 表达关系 -->
           <one-to-many class="Contact"/>
         </set>
    </class>
</hibernate-mapping>    
2.3 主配置文件
 
 
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- 4(数据库信息)+1(数据库方言)+2(生成sql格式化并打印)+1(数据库表生成策略)+1(加载映射文件)+
1(事务隔离级别)+1(配置current_session_context) -->  
<hibernate-configuration>
<session-factory>
  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/1715_hibernate05</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.connection.password">123456</property>
  
 <!-- JBoss Tools 提示工具 -->
  <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
  
  <property name="hibernate.show_sql">true</property>
  <property name="hibernate.format_sql">true</property>
  
  <property name="hibernate.hbm2ddl.auto">update</property>
    <!-- 隔离级别 -->
  <property name="hibernate.connection.isolation">4</property>
         
  <!-- 目的:要使用getCurrentSession()获取当前线程绑定的Session,必须要做如下配置:-->
  <property name="hibernate.current_session_context_class">thread</property>
  
  
  <mapping resource="com/qf/domain/Customer.hbm.xml"/>
  <mapping resource="com/qf/domain/Contact.hbm.xml"/>
</session-factory>
</hibernate-configuration>
2.4 测试
 
 
 
@Test
    public void test001() {
         Session session = HibernateUtils.getCurrentSession();
         Transaction transaction =  session.beginTransaction();
         try {
              //1个客户
             Customer customer= new Customer();
             customer.setCust_name("阿里巴巴");
             
             
             //多个联系人,示例2个
             Contact contact1 =new Contact();
             contact1.setContact_name("马云");
             Contact contact2 =new Contact();
             contact2.setContact_name("李总");
             
             //表达多表关系
             //一对多
             //把联系人给客户添加上
             customer.getContacts().add(contact1);
             customer.getContacts().add(contact2);
             
             //多对一
             contact1.setCustomer(customer);
             contact2.setCustomer(customer);
             
             
             //持久化保存
              session.save(customer);
              session.save(contact1);
              session.save(contact2);
             
             
             transaction.commit();
        } catch (Exception e) {
            // TODO: handle exception
            if (transaction!=null) {
                transaction.rollback();
            }
        }
    }
    
    
    //给指定客户添加新的联系
    
    //持久态的对象会自动更新,已经在数据库中
    //瞬时状态和游离状态必须通过方法转化成持久态才可以保存到数据
    @Test
    public void test002() {
         Session session = HibernateUtils.getCurrentSession();
         Transaction transaction =  session.beginTransaction();
         try {
             //1.先找出客户
             Customer customer = session.get(Customer.class, 1);
            
             //2.新加联系人
             Contact contact =new Contact();
             contact.setContact_name("刘总");
             
             //表达一对多的关系
             customer.getContacts().add(contact);
             
             //表达多对一的关系
             contact.setCustomer(customer);
             
             //保存
             session.save(contact);
             
             transaction.commit();
        } catch (Exception e) {
            // TODO: handle exception
            if (transaction!=null) {
                transaction.rollback();
            }
        }
    }

3、多对多(常见的,掌握)

示例1:多个学生可以被多个老师教,多个老师可以教多个 学生;

示例2:多个用户可以有多个角色,多个角色可以有多个用户。

​ 例如:马云既是老板又是演员。李彦宏既是企业家又是老板。

1.User.java
 
 
 
public class User {
    private Integer user_id;
    private String user_name;
    private String user_pwd;
    private String user_state;//用户状态
    
    //表达User和Role的多对多的关系
    private Set<Role> roles =new HashSet<>();
     set/get.......
}
2.Role.java
 
 
 
public class Role {
    private Integer role_id;//角色编号
    private String role_name;//角色名
    private String role_memo;//角色备注
    
    //表达Role和User的多对多的关系
    private Set<User> users =new HashSet<>();
    set/get.......
}
3.User.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.qf.domain">
 <class name="User" table="user">
   <id name="user_id">
      <generator class="native"></generator>
   </id>
   <property name="user_name"></property>
   <property name="user_pwd"></property>
   <property name="user_state"></property>
   
   <!-- 表达多对多的关系  table:表示中间表的名称 
      inverse:true  不维护关系(放弃维护关系)
              false:默认false,维护关系
      -->
   <set name="roles" table="user_role" inverse="true" >
      <!--  引用已经存在的键连接当前表User-->
      <key column="user_id1"></key>
     <!-- class:与当前表要建立关系的实体类名称
          column:声明外键.表示在中间表中生成一个新的列。
                                 作为外键去连接与当前表要建立关系的表
          -->
     <many-to-many class="Role" column="role_id1"></many-to-many>
   </set>
 </class>
 
 </hibernate-mapping>  
4.Role.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.qf.domain">
 <class name="Role" table="role">
   <id name="role_id">
      <generator class="native"></generator>
   </id>
   <property name="role_name"></property>
   <property name="role_memo"></property>
   
   <!-- 表达多对多的关系  table:表示中间表的名称 -->
   <set name="users" table="user_role"  >
      <!--  引用已经存在的键连接当前表Role-->
      <key column="role_id1"></key>
     <!-- class:与当前表要建立关系的实体类名称
          column:声明外键.表示在中间表中生成一个新的列。
                                 作为外键去连接与当前表要建立关系的表
          -->
     <many-to-many class="User" column="user_id1"></many-to-many>
   </set>
 </class>
 
 </hibernate-mapping>  
5.hibernate.cfg.xml
 
 
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- 4(数据库信息)+1(数据库方言)+2(生成sql格式化并打印)+1(数据库表生成策略)+1(加载映射文件)+
1(事务隔离级别)+1(配置current_session_context) -->  
<hibernate-configuration>
<session-factory>
  <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/1715_hibernate06</property>
  <property name="hibernate.connection.username">root</property>
  <property name="hibernate.connection.password">123456</property>
  
 <!-- JBoss Tools 提示工具 -->
  <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
  
  <property name="hibernate.show_sql">true</property>
  <property name="hibernate.format_sql">true</property>
  
  <property name="hibernate.hbm2ddl.auto">update</property>
    <!-- 隔离级别 -->
  <property name="hibernate.connection.isolation">4</property>
         
  <!-- 目的:要使用getCurrentSession()获取当前线程绑定的Session,必须要做如下配置:-->
  <property name="hibernate.current_session_context_class">thread</property>
  
  <mapping resource="com/qf/domain/User.hbm.xml"/>
  <mapping resource="com/qf/domain/Role.hbm.xml"/>
</session-factory>
</hibernate-configuration>
6.测试
 
 
 
   //插入
    @Test
    public void test01() {
        Session session =  HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        try {
            User user1 =new User();
            user1.setUser_name("马云11111");
            
            User user2 =new User();
            user2.setUser_name("李彦宏1111");
                    
            Role role1 =new Role();
            role1.setRole_name("企业家11111");
            
            
            Role role2 =new Role();
            role2.setRole_name("演员11111");  
            
            //表达多对多的关系  
            //从user角度出发表达关系
            user1.getRoles().add(role1);
            user1.getRoles().add(role2);
            
            user2.getRoles().add(role1);
            user2.getRoles().add(role2);
            
            
            //从role角度出发表达关系
            role1.getUsers().add(user1);
            role1.getUsers().add(user2);
            
            role2.getUsers().add(user1);
            role2.getUsers().add(user2);
            
            
            session.save(user1);
            session.save(user2);
                    
            session.save(role1);
            session.save(role2);
            
            transaction.commit();
        } catch (Exception e) {
            // TODO: handle exception
            if (transaction!=null) {
                transaction.rollback();
            }
        }
    }
执行以上代码报错:约束异常。
  解决方式一:去除掉一方关系表达维护,例如:删除掉30-34行代码
  解决方式二:代码不用改变,在不需要维护关系的地方添加inverse="true"(谁放弃给谁加)
            示例:User维护User和Role的关系。    Role放弃关系维护。
      <set name="roles" table="user_role" inverse="true" >
      <!--  引用已经存在的键连接当前表User-->
      <key column="user_id1"></key>
     <!-- class:与当前表要建立关系的实体类名称
          column:声明外键.表示在中间表中生成一个新的列。
                                 作为外键去连接与当前表要建立关系的表
          -->
     <many-to-many class="Role" column="role_id1"></many-to-many>
     </set>       
            
  备注:inverse
               true:放弃维护关系
               false:维护关系  ,默认        
7.cascade级联操作(多表关系)
 
 
 
/* cascade:级联操作   
 *       save-update(重点): 级联更新 .持久化当前对象的同时要持久化与之相关联的对象。
 *                   示例:session.save(User)  含义:持久化User的同时在持久化与User关联的类Role
               在以上案例中可以去除40行和41行
 *       delete: 级联删除    删除一个对象的同时会删除掉与之相关连的对象  (不建议使用,慎重使用)    
 *       all:  save-update和delete结合一起
 */
      //删除用户(使用cascade="delete"会删除调用当前数据和与之关联的所有数据)
        @Test
        public void test02() {
            Session session =  HibernateUtils.getCurrentSession();
            Transaction transaction = session.beginTransaction();
            try {
                 //删除一个用户
                User user = session.get(User.class, 3);
                session.delete(user);//删除user的同时删除了该user关联的role角色
        
                transaction.commit();
            } catch (Exception e) {
                // TODO: handle exception
                if (transaction!=null) {
                    transaction.rollback();
                }
            }
        }
        
        //给用户删除指定角色(不使用cascade="delete"删除)
        @Test
        public void test03() {
            Session session =  HibernateUtils.getCurrentSession();
            Transaction transaction = session.beginTransaction();
            try {
                 //一个用户
                User user = session.get(User.class, 5);
                //给该用户删除一个角色
                Role role= session.get(Role.class, 6);              
                 //从用户移除角色
                user.getRoles().remove(role);//内连接查询            
                session.delete(role);   
                transaction.commit();
            } catch (Exception e) {
                // TODO: handle exception
                if (transaction!=null) {
                    transaction.rollback();
                }
            }
        }
8.练习
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值