一、一对多关系
1.概念
一对多关系是关系型数据库中两个表之间的一种关系。通常在数据库层级中,两表之间是有主外键关系的。在ORM中,如何通过对象描述表之间的关系,是ORM核心。
2.Hibernate的一对多关联映射【重点】
2.1表关系的分析
MySql语句
CREATE TABLE `t_category` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `cname` varchar(255) DEFAULT NULL, PRIMARY KEY (`cid`));CREATE TABLE `t_product` ( `pid` int(11) NOT NULL AUTO_INCREMENT, `pname` varchar(255) DEFAULT NULL, `price` double DEFAULT NULL, `cid` int(11) DEFAULT NULL, PRIMARY KEY (`pid`), KEY `FKq8yr5sflwtcj3jqp58x0oy7lx` (`cid`), CONSTRAINT `FKq8yr5sflwtcj3jqp58x0oy7lx` FOREIGN KEY (`cid`) REFERENCES `t_category` (`cid`));
2.2创建持久化类
-
Category.java(一的一方)
1 public class Category { 2 private Integer cid; 3 private String cname; 4 //在一的一方,用一个集合表示和product的关系 5 private Set
products = new HashSet (); 6 7 public Integer getCid() { 8 return cid; 9 }10 public void setCid(Integer cid) {11 this.cid = cid;12 }13 public String getCname() {14 return cname;15 }16 public void setCname(String cname) {17 this.cname = cname;18 }19 public Set getProducts() {20 return products;21 }22 public void setProducts(Set products) {23 this.products = products;24 }25 } -
Product.java(多的一方)
1 public class Product { 2 private Integer pid; 3 private String pname; 4 private double price; 5 //用一个对象表示,当前商品属于哪个类别 6 private Category category; 7 8 public Integer getPid() { 9 return pid;10 }11 12 public void setPid(Integer pid) {13 this.pid = pid;14 }15 16 public String getPname() {17 return pname;18 }19 20 public void setPname(String pname) {21 this.pname = pname;22 }23 24 public double getPrice() {25 return price;26 }27 28 public void setPrice(double price) {29 this.price = price;30 }31 32 public Category getCategory() {33 return category;34 }35 36 public void setCategory(Category category) {37 this.category = category;38 }39 40 }
2.3创建映射
-
分类的映射
-
商品的映射
2.4将映射添加到配置文件
2.5写代码测试
-
TestDb
public class TestDb { @Test public void fun01(){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); transaction.commit(); session.close(); }}
3.级联操作
3.1概念
如果我们对某一个表进行了操作,那么也会顺带对关联表进行操作。或者说当对主对象进行某种操作时是也对其关联的从对象也作类似的操作.
eg:如果我们删除了一个公司,那么就得要求,员工表也得把属于这个公司的所有员工也删除掉。
如果我们删除了一个类别, 那么该类别下的商品是否要删除或者不删除只删除外键,那么这样的操作就属于级联操作了.
3.2 级联保存和修改
3.2.1 操作一方级联保存多方【掌握】
-
保存Category(一的一方)的时候级联保存Product(多的一方)
-
应用场景: 保存一方的同时也需要保存多方(并且多方的数据比较多). eg: 订单和订单项
-
1 /** 2 * 只保存分类,通过级联把当前分类下的商品也保存 3 * 配置: 在category.hbm.xml下设置: 4 *5 */ 6 @Test 7 public void fun02(){ 8 Session session = HibernateUtils.openSession(); 9 Transaction transaction = session.beginTransaction();10 11 Category c1 = new Category();12 c1.setCname("水果");13 14 Product p1 = new Product();15 p1.setPname("苹果");16 p1.setPrice(5);17 18 //c1和p1 产生关系19 c1.getProducts().add(p1);20 //p1和c1产生关系21 p1.setCategory(c1);22 session.save(c1);23 //session.save(p1);不需要了,通过级联保存特性自动保存24 transaction.commit();25 session.close();26 }
3.2.2操作多方级联保存一方【了解】
-
保存Product(多的一方的)的时候级联保存Category(一的一方)
1 /** 2 * 只保存商品,通过级联的特性保存商品对应的分类 3 * 配置: 在product.hbm.xml下设置: 4 *
5 */ 6 @Test 7 public void fun03(){ 8 Session session = HibernateUtils.openSession(); 9 Transaction transaction = session.beginTransaction();10 11 Category c1 = new Category();12 c1.setCname("水果");13 14 Product p1 = new Product();15 p1.setPname("苹果");16 p1.setPrice(5);17 18 //p1和c1发生关系19 p1.setCategory(c1);20 21 session.save(p1);22 23 //session.save(c1); 不需要了24 25 transaction.commit();26 session.close();27 }
3.3级联删除
3.3.1删除一方级联删除多方【掌握】
-
删除Category(一的一方)的时候级联删除Product(多的一方)
-
场景: 删除一方的时候确保多方的数据没有任何用途的时候的才会用. eg: 公司和员工
-
实际开发里面很少删除用户的数据. 通常用一个字段标识的
-
-
1 @Test 2 //级联删除商品: 删除id为1的类别,级联删除当前类别下的所有商品 3 //因为删除的是类别,所有在Category.hbm.xml配置:
4 public void fun03(){ 5 Session session = HibernateUtils.getCurrentSession(); 6 Transaction transaction = session.beginTransaction(); 7 8 //先查 id为1的类别 9 Category category = session.get(Category.class, 1);10 session.delete(category);11 transaction.commit();12 }
3.3.2 删除多方级联删除一方【了解】
-
删除Product(多的一方)的时候级联删除Category(一的一方)
1 @Test 2 //级联删除分类: 删除id为1的商品,级联删除这个商品所属的类别(了解) 3 //把当前id为1商品删除,把这个商品所属的类别删除, 商品表里面该类别其它的商品的记录的外键置为null; 4 public void fun04(){ 5 Session session = HibernateUtils.getCurrentSession(); 6 Transaction transaction = session.beginTransaction(); 7 8 //先查 id为1的类别 9 Product product = session.get(Product.class, 1);10 session.delete(product);11 12 13 transaction.commit();14 }
4.外键维护
4.1 双向关联产生多余的SQL语句
一旦存在主外键关系,那么外键就由双方对象去维护了, 那么就会造成对这个外键执行了多次操作, 有一次操作其实可以避免的。 也就是说这个外键只要让一个人去维护即可。 外键属于谁,就让谁去维护。
-
eg:修改产品对应的类别
4.2inverse标签属性
4.2.1概念
inverse
:外键维护,默认为false。代表一方不去维护多方外键。(inverse有反转的意思)
外键属于谁, 谁就负责维护.
4.2.2一方的放弃外键维护
-
只能在一的一方放弃外键维护
... -
EG:
-
1 /** 2 * 把苹果(p1)的类别设置为水果(c2) 3 * 衣服是(c1) 4 */ 5 @Test 6 public void fun02(){ 7 Session session = HibernateUtils.openSession(); 8 Transaction transaction = session.beginTransaction(); 9 //获得苹果10 Product p1 = session.get(Product.class, 1);11 //获得食物类别12 Category c2 = session.get(Category.class, 2);13 14 //p1和c2关联15 p1.setCategory(c2);16 //c2和p1关联17 c2.getProducts().add(p1);18 19 transaction.commit();20 session.close();21 }
二、多对多的关系
1.概念
多对多关系是关系数据库中两个表之间的一种数据关系,为了维护这种关系,通常会存在一张中间关系表。两张表都只和关系表间建立主外键关系。
2.Hibernate的多对多关联映射【重点】
2.1表关系的分析
-
MySql语句
2.2创建实体
-
Student.java
1 public class Student { 2 3 private Integer sid; 4 private String sname; 5 6 private Set
courses = new HashSet (); 7 8 public Integer getSid() { 9 return sid;10 }11 12 public void setSid(Integer sid) {13 this.sid = sid;14 }15 16 public String getSname() {17 return sname;18 }19 20 public void setSname(String sname) {21 this.sname = sname;22 }23 24 public Set getCourses() {25 return courses;26 }27 28 public void setCourses(Set courses) {29 this.courses = courses;30 }31 32 33 34 }
-
Course.java
1 public class Course { 2 3 private Integer cid; 4 private String cname; 5 6 private Set
students = new HashSet (); 7 8 public Integer getCid() { 9 return cid;10 }11 12 public void setCid(Integer cid) {13 this.cid = cid;14 }15 16 public String getCname() {17 return cname;18 }19 20 public void setCname(String cname) {21 this.cname = cname;22 }23 24 public Set getStudents() {25 return students;26 }27 28 public void setStudents(Set students) {29 this.students = students;30 }31 32 }
2.3创建映射
-
学生的映射
1
2 3 4 245 7 86 9 10 11 14 15 16 2317 21 22 -
课程的映射
1
2 3 4 245 7 86 9 10 11 14 15 16 2317 21 22
2.4将映射添加到配置文件
2.5写代码测试
-
保存
1 /** 2 * 正常保存 3 */ 4 @Test 5 public void fun01(){ 6 Session session = HibernateUtils.openSession(); 7 Transaction transaction = session.beginTransaction(); 8 9 Student s1 = new Student();10 s1.setSname("张三");11 Student s2 = new Student();12 s2.setSname("李四");13 14 Course c1 = new Course();15 c1.setCname("C语言");16 Course c2 = new Course();17 c2.setCname("Java");18 Course c3 = new Course();19 c3.setCname("前端");20 21 //s1选择了c1和c222 s1.getCourses().add(c1);23 s1.getCourses().add(c2);24 25 //s2选择了c2 c326 s2.getCourses().add(c2);27 s2.getCourses().add(c3);28 29 //c1被s1选了30 c1.getStudents().add(s1);31 //c2被s1,s2选了32 c2.getStudents().add(s1);33 c2.getStudents().add(s2);34 //c3被s2选了35 c3.getStudents().add(s2);36 //如果双向关联,一定要一方放弃主键维护37 session.save(s1);38 session.save(s2);39 session.save(c1);40 session.save(c2);41 session.save(c3);42 43 transaction.commit();44 session.close();45 }
3.级联操作
3.1级联保存【掌握】
-
保存Student级联保存Course
-
1 /** 2 * 保存Student级联保存Course 3 * 在student.hbm.xml里面配置:4 */ 5 @Test 6 public void fun02(){ 7 Session session = HibernateUtils.openSession(); 8 Transaction transaction = session.beginTransaction(); 9 10 Student s1 = new Student();11 s1.setSname("张三");12 Student s2 = new Student();13 s2.setSname("李四");14 15 Course c1 = new Course();16 c1.setCname("C语言");17 Course c2 = new Course();18 c2.setCname("Java");19 Course c3 = new Course();20 c3.setCname("前端");21 22 //s1选择了c1和c223 s1.getCourses().add(c1);24 s1.getCourses().add(c2);25 26 //s2选择了c2 c327 s2.getCourses().add(c2);28 s2.getCourses().add(c3);29 30 //c1被s1选了31 c1.getStudents().add(s1);32 //c2被s1,s2选了33 c2.getStudents().add(s1);34 c2.getStudents().add(s2);35 //c3被s2选了36 c3.getStudents().add(s2);37 //如果双向关联,一定要一方放弃外键维护38 session.save(s1);39 session.save(s2);40 /* session.save(c1);41 session.save(c2);42 session.save(c3);*/43 44 transaction.commit();45 session.close();46 }
-
保存Course级联保存Student
-
1 /** 2 * 保存Course级联保存Student 3 * 在Course.hbm.xml里面配置:4 */ 5 @Test 6 public void fun03(){ 7 Session session = HibernateUtils.openSession(); 8 Transaction transaction = session.beginTransaction(); 9 10 Student s1 = new Student();11 s1.setSname("张三");12 Student s2 = new Student();13 s2.setSname("李四");14 15 Course c1 = new Course();16 c1.setCname("C语言");17 Course c2 = new Course();18 c2.setCname("Java");19 Course c3 = new Course();20 c3.setCname("前端");21 22 //s1选择了c1和c223 s1.getCourses().add(c1);24 s1.getCourses().add(c2);25 26 //s2选择了c2 c327 s2.getCourses().add(c2);28 s2.getCourses().add(c3);29 30 //c1被s1选了31 c1.getStudents().add(s1);32 //c2被s1,s2选了33 c2.getStudents().add(s1);34 c2.getStudents().add(s2);35 //c3被s2选了36 c3.getStudents().add(s2);37 //如果双向关联,一定要一方放弃主键维护38 /*session.save(s1);39 session.save(s2);*/40 session.save(c1);41 session.save(c2);42 session.save(c3);43 44 transaction.commit();45 session.close();46 }
注意的地方:
如果双向关联,一定要一方放弃主键维护
3.2级联删除【了解】
-
删除Student,级联删除Course 高数
1 /** 2 * 配置了级联删除 在Student.hbm.xml配置
3 * 把id为1的学生删除, 4 * id为1的学生之前选过: id位1,2的课程. 5 * 级联删除既会删除正向多方数据库表中的记录,也会删除反向多方表中的记录和中间关系表中的记录 6 */ 7 @Test 8 public void fun02(){ 9 Session session = HibernateUtils.openSession();10 Transaction transaction = session.beginTransaction();11 12 Student student = session.get(Student.class, 1);13 session.delete(student);14 15 transaction.commit();16 session.close();17 }
注意的地方:
非级联删除只会删除正向多方数据库表和中间关系表中的记录,不会删除反向多方表中的记录
级联删除既会删除正向多方数据库表中的记录,也会删除反向多方表中的记录和中间关系表中的记录
开发过程中用的比较少
3.3其它操作
-
某个学生退课
1 /** 2 * 某个学生退课 3 * id为1的学生之前选过: id为1,2的课程. 4 * 现在的操作是:id为1的学生退掉ID为2的课程 5 */ 6 @Test 7 public void fun01(){ 8 Session session = HibernateUtils.openSession(); 9 Transaction transaction = session.beginTransaction();10 //获得id为1的学生11 Student s1 = session.get(Student.class, 1);12 13 //获得id为2的课程14 Course c2 = session.get(Course.class, 2);15 16 s1.getCourses().remove(c2);17 transaction.commit();18 session.close();19 }
-
某个学生改课
1 /** 2 * 某个学生退课 3 * id为1的学生之前选过: id为1,2的课程. 4 * 现在的操作是:id为1的学生把id为2的课程改成id为3的课程 5 */ 6 @Test 7 public void fun02(){ 8 Session session = HibernateUtils.openSession(); 9 Transaction transaction = session.beginTransaction();10 //获得id为1的学生11 Student s1 = session.get(Student.class, 1);12 //获得id为2的课程13 Course c2 = session.get(Course.class, 2);14 Course c3 = session.get(Course.class, 3);15 16 s1.getCourses().remove(c2);17 s1.getCourses().add(c3);18 transaction.commit();19 session.close();20 }