hibernate 一对多、多对多操作

表之间的关系

  1. 一对多

    一个部门有多个员工,一个员工只能属于某一个部门
    一个班级有多个学生,一个学生只能属于一个班级

  2. 多对多

    一个老师教多个学生,一个学生可以被多个老师教
    一个学生可以先择多门课程,一门课程可以被多个学生选择
    一个用户可以选择多个角色,一个角色也可以被多个用户选择

  3. 一对一

    一个公司只能对应一个注册地址

表之间关系建表原则

  1. 一对多

    在多的一方创建一个外键,指向一的一方的主键

  2. 多对多

    创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键

  3. 一对一

    唯一外键对应或主键对应

多表操作

一对多
  1. 建立表

    CREATE TABLE `linkman` (
      `link_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
      `link_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
      `link_cust_id` bigint(32) NOT NULL COMMENT '客户id',
      `link_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
      `link_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
      `link_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
      `link_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
      `link_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
      `link_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
      `link_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
      PRIMARY KEY (`link_id`)
    ) comment '联系人表' ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    CREATE TABLE `customer` (
      `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
      `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
      `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
      `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
      `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
      `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
      `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
      PRIMARY KEY (`cust_id`)
    ) comment '客户表' ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
  2. 创建实体类并设置表之间的关系

    /**
     * 客户实体类
     * @author zhou
     * @create 2019/11/19/21:33
     * @class com.zhou.domian.Linkman
     */
    @Getter
    @Setter
    public class Customer {
    
        private long cust_id;
        private String cust_name;
        private String cust_source;
        private String cust_industry;
        private String cust_level;
        private String cust_phone;
        private String cust_mobile;
    
        // 一个客户有多个联系人
        private Set<Linkman> linkmens = new HashSet<>();
    
    }
    
    /**
     * 联系人实体类
     * @author zhou
     * @create 2019/11/19/21:11
     * @class com.zhou.domian.Linkman
     */
    @Getter
    @Setter
    public class Linkman {
        private Long link_id;
        private String link_name;
        private String link_gender;
        private String link_phone;
        private String link_mobile;
        private String link_email;
        private String link_qq;
        private String link_position;
        private String link_memo;
    
        // 联系人表关联一个客户
        private Customer customer;
    }
    
  3. 创建映射文件

    <?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>
    
    <class name="com.zhou.domian.Customer" table="customer" schema="hibernate">
        <!-- 建立那个字段是主键 -->
        <id name="cust_id" column="cust_id" >
            <!-- 主键的生成策略 -->
            <generator class="native"/>
        </id>
        <!-- 建立POJO类字段和数据库字段关联 -->
        <property name="cust_name" column="cust_name"/>
        <property name="cust_source" column="cust_source"/>
        <property name="cust_industry" column="cust_industry"/>
        <property name="cust_level" column="cust_level"/>
        <property name="cust_phone" column="cust_phone"/>
        <property name="cust_mobile" column="cust_mobile"/>
    
        <!-- set标签的name属性: 多的一方的集合的属性名称  -->
        <set name="linkmens">
            <!-- key的 column表示多的一方外键名 -->
            <key column="link_cust_id"></key>
            <!-- one-to-many的class属性表示多的一方类的全限定名 -->
            <one-to-many class="com.zhou.domian.Linkman"></one-to-many>
        </set>
    </class>
    
    </hibernate-mapping>
    
    <?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>
    
        <class name="com.zhou.domian.Linkman" table="linkman" schema="hibernate">
            <id name="link_id" column="link_id">
                <generator class="native"></generator>
            </id>
            <property name="link_name" column="link_name"/>
            <property name="link_gender" column="link_gender"/>
            <property name="link_phone" column="link_phone"/>
            <property name="link_mobile" column="link_mobile"/>
            <property name="link_email" column="link_email"/>
            <property name="link_qq" column="link_qq"/>
            <property name="link_position" column="link_position"/>
            <property name="link_memo" column="link_memo"/>
    
            <!--多对一
                name: 一的一方对象的名字
                class: 一的一方类的全限定名
                column: 多的一方外键ID的名称
            -->
            <many-to-one name="customer" column="link_cust_id" class="com.zhou.domian.Customer" />
        </class>
    
    </hibernate-mapping>
    
  4. 创建核心配置文件

    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <!-- 设置连接数据库的url和用户名和密码和数据库驱动-->
            <property name="url">jdbc:mysql:///hibernate</property>
            <property name="username">root</property>
            <property name="password">123456</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <!-- 打印SQL语句 -->
            <property name="hibernate.show_sql">true</property>
            <!-- 格式化SQL -->
            <property name="hibernate.format_sql">true</property>
            <!-- 设置hibernate的方言 -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
            <!-- 设置自动创建表 -->
            <property name="hibernate.hbm2ddl.auto">create</property>
    
            <!--阿里巴巴 Druid 连接池 注意:如果使用Druid连接池的话需要把数据基本连接属性改为Druid的属性-->
            <property name="hibernate.connection.provider_class">
                com.alibaba.druid.support.hibernate.DruidConnectionProvider
            </property>
    
            <!-- 配置初始化大小、最小、最大 -->
            <property name="initialSize">1</property>
            <property name="minIdle">5</property>
            <property name="maxActive">20</property>
            <!-- 配置获取连接等待超时的时间 -->
            <property name="maxWait">60000</property>
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis">60000</property>
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis">300000</property>
    
            <!-- 设置事务隔离级别 -->
            <property name="hibernate.connection.isolation">3</property>
    
            <!-- 创建一个session绑定到当前线程 -->
            <property name="current_session_context_class">thread</property>
    
            <!-- 加载映射(mapper)文件 -->
            <mapping resource="mapper/customer.hbm.xml"></mapping>
            <mapping resource="mapper/linkman.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>
    
  5. 引入工具类

    package com.zhou.utils;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    /**
     * @author zhou
     * @create 2019/11/12/21:21
     * @class com.zhou.utils.HibernateUtils
     */
    public class HibernateUtils {
    
        public static final SessionFactory sessionFactory;
    
        static {
            // 读取配置,并创建工厂类SessionFactory
            sessionFactory = new Configuration().configure().buildSessionFactory();
        }
    
        /**
         * 获取Session对象
         * @return Session
         */
        public static Session getSession () {
            return sessionFactory.openSession();
        }
    
        /**
         * 使用时必须要在hibernate核心配置文件中配置
         * <property name="current_session_context_class">thread</property>
         * 获取Session对象,不过是从内部已经绑定好了ThreadLocal,获取的Session对象
         * @return Session
         */
        public static Session getCurrentSession(){
            return sessionFactory.getCurrentSession();
        }
    
    }
    
  6. 编写测试类

    级联操作与懒加载

    注意: 谁需要级联操作,就在mapper(映射文件)中加cascade属性


    级联的配置属性

    6.1 级联查询与懒加载

    <many-to-one name="customer" column="link_cust_id" class="com.zhou.domian.Customer" lazy="proxy" />
    
       /**
        * @author zhou
        * @create 2019/11/19/23:15
        * @class com.zhou.test.HibernateORMTest
        */
       public class HibernateORMTest {
       
           /**
            * 级联查询与懒加载
            */
           @Test
           public void get(){
               Session session = HibernateUtils.getCurrentSession();
               Transaction transaction = session.beginTransaction();
               Linkman linkman = session.get(Linkman.class, 1L);
               transaction.commit();
       
               System.out.println(linkman.getLink_name());
               /**
                * org.hibernate.LazyInitializationException: could not initialize proxy [com.zhou.domian.Customer#1] - no Session
                * 报这个错误是因为使用hibernate默认使用了懒加载的方式,要使用到另外一个对象时才会发送SQL去查询,
                * 而getCurrentSession()方法取出来的Session在commit后,会自动把session.close()掉,所以报no session的错误
                * 如果不想要对象懒加载可以在mapper配置文件中配置,lazy: 设置是否懒加载,默认为proxy(懒加载),false为不启用懒加载
                * <many-to-one name="customer" column="link_cust_id" class="com.zhou.domian.Customer" lazy="proxy" />
                */
               System.out.println(linkman.getCustomer().getCust_name());
           }
       }
    

    6.2. 级联保存

       <set name="linkmens" cascade="save-update" lazy="false">
               <!-- key的 column表示多的一方外键名 -->
               <key column="link_cust_id"></key>
               <!-- one-to-many的class属性表示多的一方类的全限定名 -->
               <one-to-many class="com.zhou.domian.Linkman"></one-to-many>
       </set> 
    
      /**
         * @author zhou
         * @create 2019/11/19/23:15
         * @class com.zhou.test.HibernateORMTest
         */
        public class HibernateORMTest {
        
            /**
             * 一对多的级联保存save, 双向绑定,不需要设置cascade属性
             */
            @Test
            public void save () {
        
                // 获取Session对象并开启事务
                Session session = HibernateUtils.getCurrentSession();
                Transaction transaction = session.beginTransaction();
        
                // 创建实体类并设置关系
                Customer customer1 = new Customer();
                Customer customer2 = new Customer();
                Customer customer3 = new Customer();
        
                customer1.setCust_name("customer1");
                customer2.setCust_name("customer2");
                customer3.setCust_name("customer3");
        
                Linkman linkman1 = new Linkman();
                Linkman linkman2 = new Linkman();
                Linkman linkman3 = new Linkman();
        
                linkman1.setLink_name("linkman1");
                linkman2.setLink_name("linkman2");
                linkman3.setLink_name("linkman3");
        
        
                linkman1.setCustomer(customer1);
                linkman2.setCustomer(customer1);
                linkman3.setCustomer(customer3);
        
                customer1.getLinkmens().add(linkman1);
                customer1.getLinkmens().add(linkman2);
                customer2.getLinkmens().add(linkman3);
        
                // 保存数据
                session.save(customer1);
                session.save(customer2);
                session.save(customer3);
        
                session.save(linkman1);
                session.save(linkman2);
                session.save(linkman3);
        
                // 提交事务
                transaction.commit();
        
            }
        
            /**
             * 一对多的级联保存save, 单项绑定
             */
            @Test
            public void saveOne () {
        
                // 获取Session对象并开启事务
                Session session = HibernateUtils.getCurrentSession();
                Transaction transaction = session.beginTransaction();
        
                // 创建实体类并设置关系,单项绑定
                Customer customer1 = new Customer();
                Customer customer2 = new Customer();
                Customer customer3 = new Customer();
        
                customer1.setCust_name("customer1");
                customer2.setCust_name("customer2");
                customer3.setCust_name("customer3");
        
                Linkman linkman1 = new Linkman();
                Linkman linkman2 = new Linkman();
                Linkman linkman3 = new Linkman();
        
                linkman1.setLink_name("linkman1");
                linkman2.setLink_name("linkman2");
                linkman3.setLink_name("linkman3");
        
                /**
                 * java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance -
                 * save the transient instance before flushing: com.zhou.domian.Linkman
                 * 持久态对象关联了一个瞬时态对象,就会报瞬时对象异常
                 * 如果想要支持单项绑定,在mapper配置文件中添加cascade="save-update"
                 * set标签的name属性: 多的一方的集合的属性名称
                 * <set name="linkmens" cascade="save-update">
                 *      key的 column表示多的一方外键名
                 *      <key column="link_cust_id"></key>
                 *       one-to-many的class属性表示多的一方类的全限定名
                 *      <one-to-many class="com.zhou.domian.Linkman"></one-to-many>
                 * </set>
                 *
                 */
                customer1.getLinkmens().add(linkman1);
                customer1.getLinkmens().add(linkman2);
                customer2.getLinkmens().add(linkman3);
        
                // 保存数据
                session.save(customer1);
                session.save(customer2);
                session.save(customer3);
        
                // 提交事务
                transaction.commit();
        
            }
        }  
    
    

    6.3. 级联删除

           <set name="linkmens" cascade="delete" lazy="false">
               <!-- key的 column表示多的一方外键名 -->
               <key column="link_cust_id"></key>
               <!-- one-to-many的class属性表示多的一方类的全限定名 -->
               <one-to-many class="com.zhou.domian.Linkman"></one-to-many>
           </set>
    
       public class HibernateORMTest {
    
           /**
            * 级联删除
            */
           @Test
           public void delete() {
               // 获取Session对象并开启事务
               Session session = HibernateUtils.getCurrentSession();
               Transaction transaction = session.beginTransaction();
               // 进行查询并删除,如果没有设置级联属性则不会级联删除,只会把附属表的属性先更新为null,在删除主表中的数据
               Customer customer = session.get(Customer.class, 1L);
               session.delete(customer);
               // 提交事务
               transaction.commit();
           }
       }
    

    6.4. 外键维护权inverse

       <!-- inverse="true" 使对象放弃外键维护-->
       <!-- set标签的name属性: 多的一方的集合的属性名称  -->
       <set name="linkmens" cascade="save-update, delete" inverse="true" lazy="false">
           <!-- key的 column表示多的一方外键名 -->
           <key column="link_cust_id"></key>
           <!-- one-to-many的class属性表示多的一方类的全限定名 -->
           <one-to-many class="com.zhou.domian.Linkman"></one-to-many>
       </set>
    
     public class HibernateORMTest{
          /**
           * 级联更新外键
           * inverse外加维护权,双向绑定使用
           */
          @Test
          public void updateInverse() {
              // 获取Session对象并开启事务
              Session session = HibernateUtils.getCurrentSession();
              Transaction transaction = session.beginTransaction();
              Customer customer2 = session.get(Customer.class, 2L);
              Linkman linkman2 = session.get(Linkman.class, 2L);
              // 双向绑定,如果双向绑定,hibernate会发送两个sql来更改同一个数据,这就造成数据库的压力,需要进行优化
              // 如果想要优化,那就让一方放弃外键维护,需要设置inverse属性让一方放弃,默认是false,false是不放弃, true是放弃
              customer2.getLinkmens().add(linkman2);
              linkman2.setCustomer(customer2);
              // 提交事务
              transaction.commit();
      
          }
      
          /**
           * 级联更新外键
           * 单项绑定
           */
          @Test
          public void update() {
              // 获取Session对象并开启事务
              Session session = HibernateUtils.getCurrentSession();
              Transaction transaction = session.beginTransaction();
              Customer customer2 = session.get(Customer.class, 2L);
              Linkman linkman2 = session.get(Linkman.class, 2L);
              // 单项绑定, 只需要一个对象进行绑定.
              customer2.getLinkmens().add(linkman2);
              // linkman2.setCustomer(customer2);
              // 提交事务
              transaction.commit();
          }
     }
    
多对多
  1. 建立表

       # 用户表
           #一个用户可以有多个角色
            CREATE TABLE `user` (
                  `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
                  `user_code` varchar(255) DEFAULT NULL,
                  `user_name` varchar(255) DEFAULT NULL,
                  `user_password` varchar(255) DEFAULT NULL,
                  `user_state` varchar(255) DEFAULT NULL,
                  PRIMARY KEY (`user_id`)
                ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
        #角色表
           #一个角色可以被多个用户选择
            CREATE TABLE `role` (
                  `role_id` bigint(20) NOT NULL AUTO_INCREMENT,
                  `role_name` varchar(255) DEFAULT NULL,
                  `role_memo` varchar(255) DEFAULT NULL,
                  PRIMARY KEY (`role_id`)
                ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
       # 中间表
               CREATE TABLE `user_role` (
                 `role_id` bigint(20) NOT NULL,
                 `user_id` bigint(20) NOT NULL,
                 PRIMARY KEY (`user_id`,`role_id`),
                 CONSTRAINT `user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`),
                 CONSTRAINT `role_id_fk` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`)
               ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 
    

    关系图


    关系图.png
  2. 创建实体类并建立关系

       /**
        * @author zhou
        * @create 2019/11/24/19:33
        * @class com.zhou.domian.User
        */
       @Getter
       @Setter
       public class User {
           private long user_id;
           private String user_code;
           private String user_name;
           private String user_password;
           private String user_state;
       
           /**
            * 建立用户对应多个角色的映射
            */
           Set<Role> roles = new HashSet<>();
       }
    
       /**
        * @author zhou
        * @create 2019/11/24/19:33
        * @class com.zhou.domian.Role
        */
       @Getter
       @Setter
       public class Role {
           private long role_id;
           private String role_name;
           private String role_memo;
       
           /**
            * 建立多角色对应多用户
            */
           private Set<User> users = new HashSet<>();
       }
    
  3. 添加配置文件

    <?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>
          <class name="com.zhou.domian.User" table="user" schema="hibernate">
              <id name="user_id" column="user_id">
                  <generator class="native"></generator>
              </id>
              <property name="user_code" column="user_code"/>
              <property name="user_name" column="user_name"/>
              <property name="user_password" column="user_password"/>
              <property name="user_state" column="user_state"/>
      
      
              <!--
                  name: 是当前集合属性名称
                  table: 是多对多中间表
                  <key column="role_id"></key>
                  当前表的外键
                  <many-to-many column="role_id" class="com.zhou.domian.Role"/>
                  column: 集合中对象的外键
                  class: 集合中对象的全路径
              -->
              <set name="roles" table="user_role" cascade ="save-update">
                  <key column="user_id"></key>
                  <many-to-many class="com.zhou.domian.Role" column="role_id"/>
              </set>
          </class>
    </hibernate-mapping>  
    
    <?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>
            <class name="com.zhou.domian.Role" table="role" schema="hibernate">
                <!-- 建立那个字段是主键 -->
                <id name="role_id" column="role_id">
                    <!-- 主键的生成策略 -->
                    <generator class="native"/>
                </id>
                <!-- 建立POJO类字段和数据库字段关联 -->
                <property name="role_name" column="role_name"/>
                <property name="role_memo" column="role_memo"/>
                <!--
                    name: 是当前集合属性名称
                    table: 是多对多中间表
                    <key column=""></key>
                    当前表的外键
                    <many-to-many column="" class=""/>
                    column: 集合中对象的外键
                    class: 集合中对象的全路径
                -->
                <set name="users" table="user_role" inverse="false">
                    <key column="role_id"></key>
                    <many-to-many column="user_id" class="com.zhou.domian.User"/>
                </set>
            </class>
    </hibernate-mapping>
    
  4. 在核心配置文件当中添加两个新配置

    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <!-- 设置连接数据库的url和用户名和密码和数据库驱动-->
            <property name="url">jdbc:mysql:///hibernate</property>
            <property name="username">root</property>
            <property name="password">123456</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <!-- 打印SQL语句 -->
            <property name="hibernate.show_sql">true</property>
            <!-- 格式化SQL -->
            <property name="hibernate.format_sql">true</property>
            <!-- 设置hibernate的方言 -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>
            <!-- 设置自动创建表 -->
            <property name="hibernate.hbm2ddl.auto">update</property>
    
            <!--阿里巴巴 Druid 连接池 注意:如果使用Druid连接池的话需要把数据基本连接属性改为Druid的属性-->
            <property name="hibernate.connection.provider_class">
                com.alibaba.druid.support.hibernate.DruidConnectionProvider
            </property>
    
            <!-- 配置初始化大小、最小、最大 -->
            <property name="initialSize">1</property>
            <property name="minIdle">5</property>
            <property name="maxActive">20</property>
            <!-- 配置获取连接等待超时的时间 -->
            <property name="maxWait">60000</property>
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis">60000</property>
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis">300000</property>
    
            <!-- 设置事务隔离级别 -->
            <property name="hibernate.connection.isolation">3</property>
    
            <!-- 创建一个session绑定到当前线程 -->
            <property name="current_session_context_class">thread</property>
    
            <!-- 加载映射(mapper)文件 -->
            <!--一对多的映射文件-->
            <mapping resource="mapper/customer.hbm.xml"/>
            <mapping resource="mapper/linkman.hbm.xml"/>
            <!--添加多对多的映射文件-->
            <mapping resource="mapper/role.hbm.xml"/>
            <mapping resource="mapper/user.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>
    
    
  5. 编写测试类

    public class HibernateManyAndMany {
    
       /**
        * 双向维护
        * 级联保存,双向维护,从表开启放弃外键维护, 如在mapper映射文件中的多对多属性中加上inverse="false",放弃外键维
        * 双向维护时,必须要有一方放弃外键维护
        * 如果两边都有维护的话, 就会有重复的的记录,由于关系表是两个字段作为共同主键,不能有相同的记录
        * 解决办法
        * 通常都是让被动方放弃,用户选角色,角色为被动方
        */
        @Test
        public void save() {
            // 获取Session对象并开启事务
            Session currentSession = HibernateUtils.getCurrentSession();
            Transaction transaction = currentSession.beginTransaction();
    
            User user1 = new User();
            user1.setUser_name("user1");
            User user2 = new User();
            user2.setUser_name("user2");
            User user3 = new User();
            user3.setUser_name("user3");
    
            Role role1 = new Role();
            role1.setRole_name("施工员");
            Role role2 = new Role();
            role2.setRole_name("资料员");
            Role role3 = new Role();
            role3.setRole_name("项目经理");
    
            user1.getRoles().add(role1);
            user1.getRoles().add(role3);
            user2.getRoles().add(role1);
            user3.getRoles().add(role2);
    
            currentSession.save(user1);
            currentSession.save(user2);
            currentSession.save(user3);
            // 放弃外键维护
            currentSession.save(role1);
            currentSession.save(role2);
            currentSession.save(role3);
    
            // 提交事务
            transaction.commit();
        }
    }
    
    /**
    * @author zhou
    * @create 2019/11/24/20:01
    * @class com.zhou.test.HibarnateManyAndMany
    */
    public class HibernateManyAndMany {
       /**
        * 级联保存,单项绑定, 单项绑定需要配置cascade="save-update"
        */
       @Test
       public void saveOne() {
           // 获取Session对象并开启事务
           Session currentSession = HibernateUtils.getCurrentSession();
           Transaction transaction = currentSession.beginTransaction();
    
           User user1 = new User();
           user1.setUser_name("user1");
           User user2 = new User();
           user2.setUser_name("user2");
           User user3 = new User();
           user3.setUser_name("user3");
    
           Role role1 = new Role();
           role1.setRole_name("施工员");
           Role role2 = new Role();
           role2.setRole_name("资料员");
           Role role3 = new Role();
           role3.setRole_name("项目经理");
    
           user1.getRoles().add(role1);
           user1.getRoles().add(role3);
           user2.getRoles().add(role1);
           user3.getRoles().add(role2);
    
           currentSession.save(user1);
           currentSession.save(user2);
           currentSession.save(user3);
    
           // 提交事务
           transaction.commit();
       }
    }
    

    多对多的级联操作和一对多的级联操作是一样的

    /**
     * @author zhou
     * @create 2019/11/24/20:01
     * @class com.zhou.test.HibarnateManyAndMany
     */
    public class HibernateManyAndMany {
    
        /**
         * 添加角色,双向绑定,让一方放弃外键维护,需要设置inverse属性让一方放弃,默认是false,false是不放弃, true是放弃
         * 如果不让一方放弃外键维护的话,会报错
         */
        @Test
        public void addRole() {
            // 获取Session并开启事务
            Session session = HibernateUtils.getCurrentSession();
            Transaction transaction = session.beginTransaction();
    
            // 用户3添加角色1
            User user3 = session.get(User.class, 3L);
            Role role1 = session.get(Role.class, 1L);
            user3.getRoles().add(role1);
            role1.getUsers().add(user3);
            // 提交事务
            transaction.commit();
        }
    
    
        /**
         * 单项维护,添加角色
         */
        @Test
        public void addRoleOne() {
            // 获取Session并开启事务
            Session session = HibernateUtils.getCurrentSession();
            Transaction transaction = session.beginTransaction();
    
            // 用户3添加角色1
            User user3 = session.get(User.class, 3L);
            Role role1 = session.get(Role.class, 1L);
            user3.getRoles().add(role1);
            // 提交事务
            transaction.commit();
        }
    
    
        /**
         * 关系操作,就是操作内部的集合
         * 把用户1的角色3修改为角色2
         */
        @Test
        public void UpdateUserAndRole() {
            // 获取Session并开启事务
            Session session = HibernateUtils.getCurrentSession();
            Transaction transaction = session.beginTransaction();
    
            // 把用户1的角色3修改为角色2
            User user1 = session.get(User.class, 1L);
            Role role2 = session.get(Role.class, 2L);
            Role role3 = session.get(Role.class, 3L);
            // 删除角色2
            user1.getRoles().remove(role3);
            // 添加角色3
            user1.getRoles().add(role2);
    
            // 提交事务
            transaction.commit();
        }
    }
    
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文包括:1、一对多结构的准备2、双向关联与单向关联3、级联保存4、级联删除5、cascade 属性——级联6、i...
    廖少少阅读 1,235评论 1 6
  • 本文包括:1、Hibernate 的查询方式2、HQL (Hibernate Query Language) 查询...
    廖少少阅读 2,688评论 0 15
  • layout: posttitle: hibernatesubtitle: 用法date: ...
    虫儿飞ZLEI阅读 334评论 0 1
  • 本文包括: 1、CRM 项目的整体介绍 2、Hibernate 框架概述 3、Hibernate 快速入门 4、H...
    廖少少阅读 3,485评论 9 66
  • 本文包括:1、Hibernate的持久化类2、Hibernate 持久化对象的三个状态(难点)3、Hibernat...
    廖少少阅读 1,472评论 0 13