学习Hibernate框架笔记-第3天

Hibernate的一对多关联映射

一、数据库表与表之间的关系

1、一对多关系

  • 什么样的关系属于一对多?
    • 一个部门对应多个员工,而一个员工只能属于某一个部门。
    • 一个客户对应多个联系人,而一个联系人只能属于某一个客户。
  • 一对多的建表原则:

在这里插入图片描述

2、多对多关系

  • 什么样的关系属于多对多?
    • 一个学生可以选择多门课程,并且一门课程也可以被多个学生选择。
    • 一个用户可以选择多个角色,并且一个角色也可以被多个用户选择。
  • 多对多的建表原则:

在这里插入图片描述

3、一对一关系(了解)

  • 什么样的关系属于一对一?
    • 一个公司只能有一个注册地址,一个注册地址只能被一个公司注册。
  • 一对一的建表原则:

在这里插入图片描述
在这里插入图片描述

二、Hibernate一对多的关系配置

1、创建一个项目,引入相应jar包

2、创建数据库和表

    CREATE TABLE `cst_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`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

    CREATE TABLE `cst_linkman` (
      `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
      `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
      `lkm_cust_id` bigint(32) DEFAULT NULL COMMENT '客户id',
      `lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
      `lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
      `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
      `lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
      `lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
      `lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
      `lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
      PRIMARY KEY (`lkm_id`),
      KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
      CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

在这里插入图片描述

3、创建实体

  • 一的一方的实体(客户实体类)

在这里插入图片描述

  • 多的一方的实体(联系人实体类)

在这里插入图片描述

4、创建映射文件

  • 一的一方的映射的创建

在这里插入图片描述

  • 多的一方的映射的创建

在这里插入图片描述

5、创建核心配置文件(复制上一个项目配置好的)

6、引入工具类(复制上一个项目配置好的)

7、编写测试类

    public class HibernateDemo1 {

	@Test
	// 创建2个客户,3个联系人,并建立好他们之间的关系
	public void demo1() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		// 创建两个客户
		Customer customer1 = new Customer();
		customer1.setCust_name("王二小");
		Customer customer2 = new Customer();
		customer2.setCust_name("小螺号");
		
		// 创建三个联系人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("如花");
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("凤姐");
		LinkMan linkMan3 = new LinkMan();
		linkMan3.setLkm_name("犀利哥");
		
		// 设置客户与联系人之间的关系
		linkMan1.setCustomer(customer1);
		linkMan2.setCustomer(customer1);
		linkMan3.setCustomer(customer2);
		customer1.getLinkMans().add(linkMan1);
		customer1.getLinkMans().add(linkMan2);
		customer2.getLinkMans().add(linkMan3);
		
		// 保存数据
		session.save(linkMan1);
		session.save(linkMan2);
		session.save(linkMan3);
		session.save(customer1);
		session.save(customer2);
		
		transaction.commit();
		}
	}

三、Hibernate的一对多相关操作

1、一对多关系只保存一边是否可以:

 	@Test
 	// 测试只保存一边看是否可以
	public void demo2() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		Customer customer = new Customer();
		customer.setCust_name("李东");
		
		LinkMan linkMan = new LinkMan();
		linkMan.setLkm_name("如花");
		customer.getLinkMans().add(linkMan);
		linkMan.setCustomer(customer);
		
		// 只保存一边看是否可以:结果是不可以,会报一个瞬时对象异常,持久态关联了一个瞬时态对象。
		// session.save(customer);
		session.save(linkMan);
		
		transaction.commit();
	}

2、一对多的级联操作

  • 什么叫做级联
    • 级联指的是,操作一个对象的时候,是否会同时操作其关联的对象。
  • 级联是有方向性
    • 操作一的一方的时候,是否操作到多的一方
    • 操作多的一方的时候,是否操作到一的一方

3、级联保存或更新

  • 保存客户级联联系人
    • 在客户配置文件中加上cascade=“save-update”属性;

在这里插入图片描述

	    @Test
		/**
		 * 级联保存或更新操作:可以实现保存一边即可两边同时保存或更新操作
		 * 	保存客户级联系人,操作的主体是客户对象,需要在Customer.hbm.xml中进行配置
		 * 	<set name="linkMans" cascade="save-update">
		 */
		public void demo3() {
			Session session = HibernateUtils.getCurrentSession();
			Transaction transaction = session.beginTransaction();
	
			Customer customer = new Customer();
			customer.setCust_name("马如龙");
			
			LinkMan linkMan = new LinkMan();
			linkMan.setLkm_name("凤姐");
			
			customer.getLinkMans().add(linkMan);
			linkMan.setCustomer(customer);
			
			session.save(customer);
			
			transaction.commit();
		}
  • 保存联系人级联客户
    • 在联系人配置文件中加上cascade=“save-update”属性;

在这里插入图片描述

		@Test
			/**
			 * 级联保存或更新操作:可以实现保存一边即可两边同时保存或更新操作
			 * 	保存联系人级联系人,操作的主体是联系人对象,需要在LinkMan.hbm.xml中进行配置
			 * 	<many-to-one name="customer" cascade="save-update" class="com.heer.hibernate.demo.Customer" column="lkm_cust_id"/>
			 */
			public void demo4() {
				Session session = HibernateUtils.getCurrentSession();
				Transaction transaction = session.beginTransaction();
				
				Customer customer = new Customer();
				customer.setCust_name("李冰");
				
				LinkMan linkMan = new LinkMan();
				linkMan.setLkm_name("犀利哥");
				
				customer.getLinkMans().add(linkMan);
				linkMan.setCustomer(customer);
				
				session.save(linkMan);
				
				transaction.commit();
			}

4、测试对象的导航

     @Test
    	public void demo5() {
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		
			// 创建1个客户
			Customer customer = new Customer();
			customer.setCust_name("王二小");
			
			// 创建3个联系人
			LinkMan linkMan1 = new LinkMan();
			linkMan1.setLkm_name("如花");
			LinkMan linkMan2 = new LinkMan();
			linkMan2.setLkm_name("凤姐");
			LinkMan linkMan3 = new LinkMan();
			linkMan3.setLkm_name("犀利哥");
			
			// 设置客户与联系人之间的关系
			linkMan1.setCustomer(customer);
			customer.getLinkMans().add(linkMan2);
			customer.getLinkMans().add(linkMan3);
			
			// 双方均设置了cascade
	//		session.save(linkMan1);		// 4条insert语句
	//		session.save(customer);		// 3条insert语句
			session.save(linkMan3);		// 1条insert语句
			
			transaction.commit();
		}

5、级联删除

  • 级联删除:
    • 删除一边的时候,同时将另一方的数据也一并删除。
  • 删除客户级联删除联系人
      @Test
      /**
       * 级联删除:
       * 删除客户 级联 删除联系人,删除的主体是客户,需要在Customer.hbm.xml文件中进行配置
       * <set name="linkMans" cascade="delete">
       */
      public void demo6() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
    
      	// 没有设置级联删除,默认情况:修改了联系人的外键,删除客户
      	/*Customer customer = session.get(Customer.class, 1l);
      	session.delete(customer);*/
      	
      	// 删除客户,同时删除联系人
      	Customer customer = session.get(Customer.class, 1l);
      	session.delete(customer);
      	
      	transaction.commit();
      }
    
  • 删除联系人级联删除客户(基本不用,因为不太符合常规)
      @Test
      /**
       * 级联删除:
       * 删除联系人 级联 删除客户,删除的主体是客户,需要在LinkMan.hbm.xml文件中进行配置
       * <many-to-one name="customer" cascade="delete">
       */
      public void demo7() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
    
      	// 删除客户,同时删除联系人
      	LinkMan linkMan = session.get(LinkMan.class, 3l);
      	session.delete(linkMan);
      	
      	transaction.commit();
      }
    

6、一对多设置了双向关联产生多余的SQL语句

在这里插入图片描述

  • 解决多余的SQL语句
    • 单向维护:
    • 使一方放弃外键维护权:
      • 一的一方放弃。在set上配置inverse=”true”
    • 一对多的关联查询的修改的时候。(CRM练习)

7、区分cascade和inverse

    @Test
   	/**
   	 * 区分cascade和inverse的区别
   	 */
   	public void demo9() {
   		Session session = HibernateUtils.getCurrentSession();
   		Transaction transaction = session.beginTransaction();
		
		Customer customer = new Customer();
		customer.setCust_name("李冰");
		
		LinkMan linkMan = new LinkMan();
		linkMan.setLkm_name("犀利哥");
		
		customer.getLinkMans().add(linkMan);

		// 条件在Customer.hbn.xml上的set配置中配置了cascade="save-update" inverse="true"
		session.save(customer);		// 客户会插入到数据库,联系人二回插入到数据库,但是外键为null
		
		transaction.commit();
	}

Hibernate的多对多关联映射

一、Hibernate多对多关系的配置

1、创建表

  • 用户表
      CREATE TABLE `sys_user` (
            `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
            `user_code` varchar(32) NOT NULL COMMENT '用户账号',
            `user_name` varchar(64) NOT NULL COMMENT '用户名称',
            `user_password` varchar(32) NOT NULL COMMENT '用户密码',
            `user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
            PRIMARY KEY (`user_id`)
          ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
  • 角色表
       CREATE TABLE `sys_role` (
            `role_id` bigint(32) NOT NULL AUTO_INCREMENT,
            `role_name` varchar(32) NOT NULL COMMENT '角色名称',
            `role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
            PRIMARY KEY (`role_id`)
          ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
  • 中间表
      CREATE TABLE `sys_user_role` (
      		  `role_id` bigint(32) NOT NULL COMMENT '角色id',
      		  `user_id` bigint(32) NOT NULL COMMENT '用户id',
      		  PRIMARY KEY (`role_id`,`user_id`),
      		  KEY `FK_user_role_user_id` (`user_id`),
      		  CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
      		  CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
      		) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

2、创建实体

  • 用户的实体

在这里插入图片描述

  • 角色的实体

在这里插入图片描述

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.heer.hibernate.demo.Customer" table="cst_customer">
      		<!-- 建立OID与主键的映射 -->
      		<id name="user_id" column="user_id">
      			<generator class="native"/>
      		</id>
      		<!-- 建立普通属性与表字段的映射 -->
      		<property name="user_code"/>
      		<property name="user_name"/>
      		<property name="user_password"/>
      		<property name="user_state"/>
      		<!-- 配置角色多对多的映射关系 -->
      		<!-- 
      			set标签:
      				*name:对方的对象集合的属性名名称;
      				*table:多对多关系需要中间表,放的是中间表的名称
      		 -->
      		<set name="roles" table="sys_user_role">
      			<!-- 
      				key标签:
      					*column:当前的对象对应中间表的外键名称;
      			 -->
      			<key column="user_id"/>
      			<!-- 
      				many-to-many标签:
      					*class:对方实体类全路径;
      					*column:对方的对象在中间表中的外键名称;
      			 -->
      			 <many-to-many class="com.heer.hibernate.demo2.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.heer.hibernate.demo.Customer" table="cst_customer">
      		<!-- 建立OID与主键的映射 -->
      		<id name="role_id" column="role_id">
      			<generator class="native"/>
      		</id>
      		<!-- 建立普通属性与表字段的映射 -->
      		<property name="role_name"/>
      		<property name="role_memo"/>
      		<!-- 配置角色多对多的映射关系 -->
      		<!-- 
      			set标签:
      				*name:对方的对象集合的属性名名称;
      				*table:多对多关系需要中间表,放的是中间表的名称
      		 -->
      		<set name="users" table="sys_user_role">
      			<!-- 
      				key标签:
      					*column:当前的对象对应中间表的外键名称;
      			 -->
      			<key column="role_id"/>
      			<!-- 
      				many-to-many标签:
      					*class:对方实体类全路径;
      					*column:对方的对象在中间表中的外键名称;
      			 -->
      			 <many-to-many class="com.heer.hibernate.demo2.User" column="user_id"/>
      		</set>
      	</class>
      </hibernate-mapping>
    

4、编写测试类

  • 测试类这么下,运行会报错,需要在user的set配置中加上inverse=“true”,即让role放弃外键维护。
         @Test
       	/**
       	 * 保存多条记录,保存多个用户和角色
       	 */
       	public void demo1() {
       		Session session = HibernateUtils.getCurrentSession();
       		Transaction transaction = session.beginTransaction();
    
     		// 创建2个用户
     		User user1 = new User();
     		user1.setUser_name("张三");
     		User user2 = new User();
     		user2.setUser_name("李四");
     		
     		// 创建3个角色
     		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(role2);
     		user2.getRoles().add(role2);
     		user2.getRoles().add(role3);
     		role1.getUsers().add(user1);
     		role2.getUsers().add(user1);
     		role2.getUsers().add(user2);
     		role3.getUsers().add(user2);
     		
     		// 保存操作:多对多建立了双向的关系,所以必须有一方放弃外键维护。
     		// 一般是被动方放弃外键维护权。
     		session.save(user1);
     		session.save(user2);
    			session.save(role1);
    			session.save(role2);
    			session.save(role3);
     		
     		transaction.commit();
     	}
    

二、Hibernate的多对多的操作

1、只保存一边是否可以

	@Test
	// 测试只保存一边
	public void demo2() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
	
		User user = new User();
		user.setUser_name("王五");
		
		Role role = new Role();
		role.setRole_name("总经理");
		
		user.getRoles().add(role);
		role.getUsers().add(user);
		// 只保存用户
//		session.save(user);
		session.save(role);
		
		transaction.commit();
	}

2、多对多的级联保存或更新

  • 保存用户级联保存角色
      @Test
      // 保存用户级联角色
      public void demo3() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
    
      	User user = new User();
      	user.setUser_name("王五");
      	
      	Role role = new Role();
      	role.setRole_name("总经理");
      	
      	user.getRoles().add(role);
      	role.getUsers().add(user);
      	// 只保存用户
      	session.save(user);
      	
      	transaction.commit();
      }
    
  • 保存角色级联保存用户
      @Test
      // 保存角色级联用户
      public void demo4() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
    
      	User user = new User();
      	user.setUser_name("王五");
      	
      	Role role = new Role();
      	role.setRole_name("总经理");
      	
      	user.getRoles().add(role);
      	role.getUsers().add(user);
      	// 只保存角色
      	session.save(role);
      	
      	transaction.commit();
      }
    

3、多对多的级联删除(基本用不上)

  • 删除用户级联删除角色
      @Test
      /**
       * 多对多的级联删除
       * 删除用户级联删除角色
       * 在User.hbm.xml中的set中配置cascade="delete"
       */
      public void demo5() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
      
      	// 查询1号用户
      	User user = session.get(User.class, 1l);
      	session.delete(user);
      	
      	transaction.commit();
      }
    
  • 删除角色级联删除用户
      @Test
      /**
       * 多对多的级联删除
       * 删除角色级联删除用户
       * 在Role.hbm.xml中的set中配置cascade="delete"
       */
      public void demo6() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
      
      	// 查询1号用户
      	Role role = session.get(Role.class, 1l);
      	session.delete(role);
      	
      	transaction.commit();
      }
    

4、多对多的其他的操作

  • 给用户选择角色
      @Test
      /**
       * 给用户选择角色
       */
      public void demo7() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
      
      	// 给1号用户多选3号角色
      	// 查询1号用户
      	User user = session.get(User.class, 1l);
      	// 查询3号角色
      	Role role = session.get(Role.class, 3l);
    
      	user.getRoles().add(role);
      	
      	transaction.commit();
      }
    
  • 给用户改选角色
      @Test
      /**
       * 给用户改角色
       */
      public void demo8() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
    
      	// 将2号原有的2号角色改为3号角色
      	// 查询2号用户
      	User user = session.get(User.class, 2l);
      	// 查询2、3号角色
      	Role role1 = session.get(Role.class, 2l);
      	Role role2 = session.get(Role.class, 3l);
      	user.getRoles().remove(role1);
      	user.getRoles().add(role2);
      	
      	transaction.commit();
      }
    
  • 给用户删除角色
      @Test
      /**
       * 给用户删除角色
       */
      public void demo9() {
      	Session session = HibernateUtils.getCurrentSession();
      	Transaction transaction = session.beginTransaction();
      
      	// 将2号原有的2号角色删除
      	// 查询2号用户
      	User user = session.get(User.class, 2l);
      	// 查询2号角色
      	Role role = session.get(Role.class, 2l);
      	user.getRoles().remove(role);
      	
      	transaction.commit();
      }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值