第三次作业随想篇:Hibernate之多对多篇
Hibernate值多对多篇:
首先Hibernate基于数据库持久层框架,好的OR框架。封装了JDBC对数据库繁琐的操作,完全以面向对象的方式来操作数据库,提供了以及一级,二级缓存。
下面就来谈谈Hibernate的优点与缺点:
优点:
1.对jdbc访问数据库进行了封装,简化了繁琐的操作。
2.映射的灵活性
3.非侵入性,移植性好。(就是说只需将你的映射文件及其配置文件移植到相应另一台计算机上照样可以运行,因为表的它是自己检查创建的,这一点非常好,不像Mybatis那样,你要去建一个和他的映射文件字段,属性一样的表,才能运行,这一点比Mybatis好)
4.提供一级二级缓存。
缺点:
1.无法对SQL进行优化。
2.配置复杂。(什么一对一,一对多,多对多),这里主要针对自己手写,不过用工具根据数据库表生成实体类和映射文件就十分简单了。
3.SQL执行效率低。
4.不支持批量的删除,修改。
今天先来说说它的多对多:
这里举的例子为学生与课程的关系,一个学生可以选修多个课程,一个课程可被多个学生选择,标准的多对多关系。
配置文件如下:主要用于指明数据库连接的信息及其是否展示SQL,方言,检查更新,关联相应的映射文件。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version='1.0' encoding='utf-8'?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 6 <hibernate-configuration> 7 8 <session-factory> 9 10 <property name="connection.username">scott</property> 11 <property name="connection.password">orcl</property> 12 13 <property name="connection.url"> 14 jdbc:mysql://localhost:3306/dbs 15 </property> 16 <!-- 17 作用:根据持久化类和映射文件生成表 18 validate 在启动的时候验证持久化类和表的描述是否一样 19 create-drop 一般不用,当hibernate启动的时候生成表,结束的时候删除表 20 create 只要启动Hibernate的时候生成表 21 update 在启动时候检查持久文件和表是否对应对应则不该,不对应则新建 22 --> 23 <property name="hbm2ddl.auto">update</property> 24 <!-- 25 显示hibernate内部生成的sql语句 26 --> 27 <property name="show_sql">true</property> 28 <property name="dialect"> 29 org.hibernate.dialect.MySQLDialect 30 </property> 31 <!-- 如果映射文件有两个要注意 --> 32 <mapping resource="cn/hp/relaDemo/Students.hbm.xml" /> 33 <mapping resource="cn/hp/relaDemo/Course.hbm.xml" /> 34 </session-factory> 35 36 </hibernate-configuration>
相应的Course映射文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="utf-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 5 <hibernate-mapping> 6 7 <class name="cn.hp.relaDemo.Course"> 8 9 <id name="cid" type="java.lang.Long" length="5"> 10 <generator class="increment"></generator> 11 </id> 12 13 <property name="cname" length="10" type="java.lang.String"></property> 14 15 <property name="cdepartment" length="10" type="java.lang.String"></property> 16 17 <set name="students" table="student_course" cascade="save-update"> 18 <key> 19 <column name="cid"></column> 20 </key> 21 <many-to-many class="cn.hp.relaDemo.Students"></many-to-many> 22 </set> 23 24 </class> 25 </hibernate-mapping> 26
相应的Student映射文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="utf-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 5 <hibernate-mapping> 6 7 <class name="cn.hp.relaDemo.Students"> 8 <!-- name --> 9 <id name="sid" type="java.lang.Long" length="5"> 10 <!-- 主键的产生 --> 11 <generator class="increment"></generator> 12 </id> 13 14 <property name="sname" length="10" type="java.lang.String"></property> 15 16 <property name="description" length="10" type="java.lang.String"></property> 17 18 <!-- 多对一 的关系 19 column指明外键 20 table是用来描述第三张表的。 21 --> 22 <set name="course" table="student_course" cascade="save-update"> 23 <key> 24 <column name="sid"></column> 25 </key> 26 <!-- class指明它所指向的多对多的类,column指明此表的外键 --> 27 <many-to-many class="cn.hp.relaDemo.Course" column="cid"> 28 </many-to-many> 29 </set> 30 31 </class> 32 </hibernate-mapping> 33
相应的实体类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.hp.relaDemo; 2 3 import java.io.Serializable; 4 import java.util.Set; 5 6 public class Course implements Serializable{ 7 /** 8 * 9 */ 10 private static final long serialVersionUID = 1L; 11 //注意加的不是外键,若加的是外键则不是面向对象思想 12 private long cid; 13 private String cname; 14 private String cdepartment; 15 private Set<Students> students; 16 17 public long getCid() { 18 return cid; 19 } 20 public void setCid(long cid) { 21 this.cid = cid; 22 } 23 public String getCname() { 24 return cname; 25 } 26 public void setCname(String cname) { 27 this.cname = cname; 28 } 29 public String getCdepartment() { 30 return cdepartment; 31 } 32 public void setCdepartment(String cdepartment) { 33 this.cdepartment = cdepartment; 34 } 35 public Set<Students> getStudents() { 36 return students; 37 } 38 public void setStudents(Set<Students> students) { 39 this.students = students; 40 } 41 42 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.hp.relaDemo; 2 3 import java.io.Serializable; 4 import java.util.Set; 5 6 public class Students implements Serializable{ 7 8 private Long sid; 9 private String sname; 10 private String description; 11 private Set<Course> course; 12 13 public Long getSid() { 14 return sid; 15 } 16 public void setSid(Long sid) { 17 this.sid = sid; 18 } 19 public String getSname() { 20 return sname; 21 } 22 public void setSname(String sname) { 23 this.sname = sname; 24 } 25 public String getDescription() { 26 return description; 27 } 28 public void setDescription(String description) { 29 this.description = description; 30 } 31 public Set<Course> getCourse() { 32 return course; 33 } 34 public void setCourse(Set<Course> course) { 35 this.course = course; 36 } 37 38 39 }
用于加载配置文件及其创建SessionFactory的帮助类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.hp.test; 2 3 import org.hibernate.SessionFactory; 4 import org.hibernate.cfg.Configuration; 5 import org.junit.Before; 6 7 public class Hibernateabs { 8 protected static SessionFactory sessionFactory=null; 9 //子类和父类同时有static语句块,先执行父类的语句块 10 static String url=null; 11 /* static 12 { 13 //准备加载相应的配置文件 14 Configuration configuration=new Configuration(); 15 //加载Hibernate的配置文件 16 configuration.configure(); 17 //SessionFactory是一个 18 sessionFactory=configuration.buildSessionFactory(); 19 //打开数据库的连接准备就绪数据库的操作,查询不需开启事物 20 }*/ 21 @Before 22 public void before() 23 { 24 //准备加载相应的配置文件 25 Configuration configuration=new Configuration(); 26 //加载Hibernate的配置文件 27 configuration.configure(url); 28 //SessionFactory是一个 29 sessionFactory=configuration.buildSessionFactory(); 30 //打开数据库的连接准备就绪数据库的操作,查询不需开启事物 31 } 32 }
接下来是相应的各种测试包括级联保存,查找,删除,修改,等等。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.hp.test; 2 3 import java.util.ArrayList; 4 import java.util.HashSet; 5 import java.util.List; 6 import java.util.Set; 7 8 import org.hibernate.Session; 9 import org.hibernate.Transaction; 10 import org.junit.Test; 11 12 import cn.hp.relaDemo.Course; 13 import cn.hp.relaDemo.Students; 14 15 /* 16 * 1.新建一个课程 17 * 2.新建一个学生 18 * 3.新建课程的同时新建学生 19 * 4.已经存在一个学生,新建一个课程,建立课程和学生之间的联系 20 * 5.已经存在一个课程,新建一个学生,建立关联 21 * 6.已经存在一个课程,已经存在一个学生,建立关联 22 * 7.把已经存在的学生加入到已经存在的课程中 23 * 8.把一个学生加入到一些课程中 24 * 9.把多个学生加入到多个课程中 25 * 10.把一个已经存在的学生从一个已经存在的课程中移除 26 * 11.把一些已经存在的学生从一个已经存在的课程中移除 27 * 12.把一个学生从一个课程转到另一个课程 28 * 13.删除课程 29 * 14.删除学生 30 */ 31 public class ManyToManyTest extends Hibernateabs{ 32 33 static{ 34 url="cn/hp/relaDemo/hibernate.cfg.xml"; 35 } 36 @Test 37 public void test1() 38 { 39 Session session=sessionFactory.openSession(); 40 Transaction transaction=session.beginTransaction(); 41 42 Students students=new Students(); 43 students.setDescription("desc33"); 44 students.setSname("hepanhen"); 45 46 Course course=new Course(); 47 course.setCname("niybi"); 48 course.setCname("xoaoniu"); 49 50 Set<Course>courses=new HashSet<Course>(); 51 courses.add(course); 52 53 students.setCourse(courses); 54 session.save(students); 55 transaction.commit(); 56 session.close(); 57 } 58 59 /* 60 * 已经存在一个课程,新建一个学生,建立关联 61 * 从学生角度出发 62 */ 63 @Test 64 public void test2() 65 { 66 Session session=sessionFactory.openSession(); 67 Transaction transaction=session.beginTransaction(); 68 69 Students students=new Students(); 70 students.setDescription("鸟人"); 71 students.setSname("name"); 72 73 //先得到学生 74 Course course=(Course) session.get(Course.class, 1L); 75 76 Set<Course> courses=new HashSet<Course>(); 77 courses.add(course); 78 students.setCourse(courses); 79 80 session.save(students); 81 transaction.commit(); 82 session.close(); 83 } 84 85 /* 86 * 已经存在一个课程,已经存在一个学生,建立关联 87 * 从学生端出发,也可以从课程端出发 88 */ 89 @Test 90 public void test3() 91 { 92 Session session=sessionFactory.openSession(); 93 Transaction transaction=session.beginTransaction(); 94 95 Course course=(Course) session.get(Course.class, 2L); 96 Students students=(Students) session.get(Students.class, 3L); 97 98 students.getCourse().add(course); 99 100 transaction.commit(); 101 session.close(); 102 } 103 104 /* 105 * 把多个学生加入到一个课程中,注意效率的问题 106 */ 107 @Test 108 public void test4() 109 { 110 Session session=sessionFactory.openSession(); 111 Transaction transaction=session.beginTransaction(); 112 113 Students student4=(Students) session.get(Students.class, 4L); 114 Students student5=(Students) session.get(Students.class, 5L); 115 Course course=(Course) session.get(Course.class, 3L); 116 course.getStudents().add(student5); 117 //又取一次是不会发出Sql语句,course.getStudents(),性能的优化问题。 118 course.getStudents().add(student4); 119 120 transaction.commit(); 121 session.close(); 122 } 123 124 /* 125 * 把一个学生加入到一些课程中,从学生端出发比较简单 126 */ 127 @Test 128 public void test5() 129 { 130 Session session=sessionFactory.openSession(); 131 Transaction transaction=session.beginTransaction(); 132 133 Students student4=(Students) session.get(Students.class, 4L); 134 List <Course> course=session.createQuery("from Course where cid= 1 or cid =2 or cid=3").list(); 135 //又取一次是不会发出Sql语句,course.getStudents(),性能的优化问题。 136 for(int i=0;i<course.size();i++) 137 { 138 student4.getCourse().add(course.get(i)); 139 } 140 141 transaction.commit(); 142 session.close(); 143 } 144 145 /* 146 * 把学生从一个课程转移到另一个课程,从学生端维护关系 147 * 第一种方法,直接使用Set的方法 148 */ 149 @Test 150 public void test6() 151 { 152 Session session=sessionFactory.openSession(); 153 Transaction transaction=session.beginTransaction(); 154 155 Students student4=(Students) session.get(Students.class, 2L); 156 Course course=(Course) session.get(Course.class, 3L); 157 //新建一个set集合用于添加数据 158 Set<Course> courses=new HashSet<Course>(); 159 courses.add(course); 160 161 student4.setCourse(courses); 162 163 transaction.commit(); 164 session.close(); 165 } 166 167 /* 168 * 把学生从一个课程转移到另一个课程,从学生端维护关系 169 * 第二种方法,采用先添加后移除的方法 170 */ 171 @Test 172 public void test7() 173 { 174 Session session=sessionFactory.openSession(); 175 Transaction transaction=session.beginTransaction(); 176 177 Students student4=(Students) session.get(Students.class, 2L); 178 Course course3=(Course) session.get(Course.class, 3L); 179 Course course4=(Course) session.get(Course.class, 4L); 180 student4.getCourse().remove(course3); 181 student4.getCourse().add(course4); 182 183 transaction.commit(); 184 session.close(); 185 } 186 187 /* 188 * 将选修课程一的所有学生删除,删除之前需要先解除关系 189 */ 190 @Test 191 public void test8() 192 { 193 Session session=sessionFactory.openSession(); 194 Transaction transaction=session.beginTransaction(); 195 196 Course course3=(Course) session.get(Course.class, 1L); 197 //org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): 198 //出现错误,删除学生之前需要先解除关系 199 Set<Students> students=course3.getStudents(); 200 201 for(Students stu:students) 202 { 203 course3.setStudents(null);//先解除关系/**/ 204 session.delete(stu); 205 } 206 207 transaction.commit(); 208 session.close(); 209 } 210 211 }
测试数据库是否连接成功的单元测试类。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package cn.hp.test; 2 3 import org.junit.Test; 4 5 public class CreatTable extends Hibernateabs{ 6 7 static{ 8 url="cn/hp/relaDemo/hibernate.cfg.xml"; 9 } 10 @Test 11 public void testcreate() 12 { 13 System.out.println("shujuku succeed..."); 14 } 15 16 }
连接成功打印出
运行第一个单元测试用例:控制台输出:
显示数据插入插入成功:
打开数据库,果然相应的数据已经插入数据库
其他的单元测试用例自己去测吧。
注意:
这里要注意级联和维护外键的问题。
若要通过保存学生级联保存他所选的课程,就需要,设置相应的cascade="save-update"属性,若果你没有设置级联保存,他就告诉你没有没法保存。
错误信息如下: