Hibernate-多表关系

多表关系映射

1.一对一(会用即可)

主表:没有外键 有主键
从表:拥有外键的是从表
先操作从表,再去操作主表
one-to-one  ,many-to-one 只是表达多个表之间的关系。
外键:目的是多表连接
主键:目的是唯一标识数据
1.1 方式一: 按照主键映射 (主键都是一样的)
用已有的主键充当外键去连接表来表示关系
方式二:按照外键映射
给表额外插入一个列作为外键去连接另一个表

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;

//主表
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.....
}
映射文件  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>
多对多:

示例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();
                    }
                }
            }
原文地址:https://www.cnblogs.com/a77355699/p/7905935.html