Hibernate框架(3)

 

 

1.Hibernate的一对多

             (1)表与表之间关系

                            一对多关系

                            多对多关系

                            一对一关系

             (2)Hibernate的一对多配置

                             1)搭建Hibernate基本环境

                             2)创建表

                             3) 创建实体

                                      一的一方:放的是多的一方的集合                                          

                                      多的一方:放的是一的一方的对象

                              4)  创建映射

                                      一的一方:配置的<set>集合

                                      多的一方:配置<many-to-one>

                              5)  编写测试类

             (3)Hibernate的一对多的操作

                             1) 级联操作:cascade,用于操作其关联的对象。

                                      级联保存或更新

                                      级联删除

                             2)测试对象导航

                             3)放弃外键维护权:inverse,用户控制是否有外键维护能力

 

2.Hibernate的多对多

             (1)Hibernate的多对多配置

                             1)搭建Hibernate环境

                             2)创建表

                             3)创建实体:放置的是对方的集合

                             4)创建映射:配置的是对象的<set>

                             4)编写测试类

             (2)Hibernate的多对多操作

                             1)级联操作

                                       级联保存或更新

                                       级联删除(了解)

                             2)其他的操作

                                       给用户选择角色

                                       给用户改选角色

                                       给用户删除角色

 

 

数据库表与表之间的关系

1.一对多关系

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

 

2.多对多关系

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

3.一对一关系(了解)

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

 

 

一对多的关系配置

1.创建数据库

客户与联系人,一个客户可以拥有多个联系人,但是一个联系人只能有一个客户

客户cst_customer为一的一方,联系人cst_linkman为多的一方

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;

 

2.创建实体

这里的话多的一方的外键不是使用lik_cust_id表示,而是直接使用客户的对象来表示,因为对象的id就是多的一方的外键

3.创建映射文件

(1)多的一方的映射的创建

 

(2)一的一方的映射的创建

4.创建核心配置文件

     hibernate.cfg.xml

5.引入工具类

package com.itheima.hibernate.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Hibernate
 * @author jt
 *
 */
public class HibernateUtils {

	public static final Configuration cfg;
	public static final SessionFactory sf;
	
	static{
		cfg = new Configuration().configure();
		sf = cfg.buildSessionFactory();
	}
	
	public static Session openSession(){
		return sf.openSession();
	}
	
	public static Session getCurrentSession(){
		return sf.getCurrentSession();
	}
}

6.编写测试类

package com.itheima.hibernate.demo1;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.hibernate.domain.Customer;
import com.itheima.hibernate.domain.LinkMan;
import com.itheima.hibernate.utils.HibernateUtils;

/**
 * 一对多的测试类
 * @author jt
 *
 */
public class HibernateDemo1 {

	@Test
	// 保存2个客户  和 3个联系人  并且建立好关系
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = 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);
		
		tx.commit();
	}

一对多只保存一边可以吗?

7.一对多的级联操作

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

(例如我们在将想要将一个客户进行删除,那么联动的就需要删除与这个客户相关的联系人,如果我们将联系人和客户用原始的方式进行删除,代码量将会很多。级联相当于我们删除客户会连同其联系人一起删除,反之亦然)

  • 级联是有方向性
    • 操作一的一方的时候,是否操作到多的一方
    • 操作多的一方的时候,是否操作到一的一方

 

保存客户级联联系人

这里我们看到我们只需要保存customer那么与其关联的linkMan也会被保存。

 

保存联系人级联客户

 

测试对象的导航

这里发送四条的原因是linkMan1关联了customer,而customer关联了linkMan2和linkMan3,所以一共发了四条

 

发送三条是因为customer关联了linkMan2和linkMan3,而没有关联linkMan1

 

linkMan2没有与另外三个关联,所以只发送了一条

 

级联删除

  • 级联删除:
    • 删除一边的时候,同时将另一方的数据也一并删除。
  • 删除客户级联删除联系人

 

删除联系人级联删除客户(基本不用)

 

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

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

 

区分cascadeinverse

 

 

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.创建映射

用户映射

角色映射

4.编写测试类

package com.itheima.hibernate.demo2;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.hibernate.domain.Role;
import com.itheima.hibernate.domain.User;
import com.itheima.hibernate.utils.HibernateUtils;

/**
 * Hibernate的多对多的映射
 * @author jt
 *
 */
public class HibernateDemo2 {

	@Test
	/**
	 * 保存多条记录:保存多个用户和角色
	 */
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = 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);
		
		tx.commit();
	}

不可以只保存一边

 

多对多的级联保存或更新

1.保存用户级联保存角色

 

2.保存角色级联保存用户

 

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

1.删除用户级联删除角色

2.删除角色级联删除用户

 

 

多对多的其他的操作

1.给用户选择角色

2.给用户改选角色

3.给用户删除角色