Hibernate(6)——一对多和多对多关联关系映射(xml和注解)总结涉及的知识点总结如下:OnetoMany映射关系o多对一单向外键关联(XML/Annotation)o一对多单向外键关联(XML/Annotation)o懒加载和积极加载o一对多双向外键关联(XML/Annotation)ManytoMany映射关系o多对多单向外键关联(XML/Annotation)o多对多双向外键关联(XML/Annotation)oset的inverse元素详解问题小结关联关系的优缺点多对一单向外键关联关系注意多对一关联是多方持有一方的引用。看一个例子,去淘宝购物,那么一个淘宝用户可以对应多个购物订单,如图所示:多的一方是Orders,持有一方的引用,也就是Users,而在Users中无需作任何定义,从订单到用户的关系是单向多对一关联。对应数据库就是:还有比如说学生和班级的关系,多个学生可以属于同一个班级,这就是从学生到班级也是典型的单向多对一关系,看代码实现:基于注解的多对一单向外键关联:单向多对一关联中,多方需要持有一方的引用,那么多方(学生类)需要额外配置,需要对持有的一方引用使用注解@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.EAGER),设置为级联操作和饥渴的抓取策略,@JoinColumn(name=cid),而一方(教室类)无需做任何多方的定义。注意;多方必须保留一个不带参数的构造器!importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.Id;//班级类,在多对一关系中属于一的方,不持有其他多余的配置,反而是被多方持有@EntitypublicclassClassRoom{privateintcid;//班级编号privateStringcname;//班级名称//自动增长的主键@Id@GeneratedValuepublicintgetCid(){returncid;}publicvoidsetCid(intcid){this.cid=cid;}publicStringgetCname(){returncname;}publicvoidsetCname(Stringcname){this.cname=cname;}}ViewCode一方——班级类无需做多余的定义,下面是多方——学生实体和配置:importjavax.persistence.CascadeType;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.Id;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;//学生实体类,属于多对一的多方,持有班级(一方)的引用@EntitypublicclassStudents{privateintsid;//编号privateStringsname;//姓名privateClassRoomclassroom;//学生班级//注意:多方一定要显式的定义不带参数的构造方法publicStudents(){}publicStudents(Stringsname){this.sname=sname;}//多方使用注解:@ManyToOne//fetch=FetchType.EAGER,急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。//全部级联操作,referencedColumnName显式设置数据库字段名cid,不写默认就是和name一样的。@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.EAGER)@JoinColumn(name=cid,referencedColumnName=cid)publicClassRoomgetClassroom(){returnclassroom;}publicvoidsetClassroom(ClassRoomclassroom){this.classroom=classroom;}//自动增长主键@Id@GeneratedValuepublicintgetSid(){returnsid;}publicvoidsetSid(intsid){this.sid=sid;}publicStringgetSname(){returnsname;}publicvoidsetSname(Stringsname){this.sname=sname;}}ViewCode下面测试:先生成数据库脚本,再进行学生对象的插入publicclassTestStudentsByAnno{privatestaticSessionFactorysessionFactory;@BeforepublicvoidsetUp()throwsException{System.out.println(setUp()...);sessionFactory=newAnnotationConfiguration().configure().buildSessionFactory();}@AfterpublicvoidtearDown()throwsException{System.out.println(tearDown()...);sessionFactory.close();}@TestpublicvoidtestSave(){Sessionsession=sessionFactory.getCurrentSession();Transactiontx=session.beginTransaction();try{ClassRoomc=newClassRoom();c.setCname(computer001);Studentss=newStudents(zhangsan);s.setClassroom(c);session.save(s);tx.commit();}catch(Exceptionex){ex.printStackTrace();tx.rollback();}}@Test@IgnorepublicvoidtestSchemaExport(){SchemaExportse=newSchemaExport(newAnnotationConfiguration().configure());se.create(true,true);}}ViewCode反向创建表的数据库脚本如下:createtableClassRoom(cidintegernotnullauto_increment,cnamevarchar(255),primarykey(cid))createtableStudents(sidintegernotnullauto_increment,snamevarchar(255),cidinteger,primarykey(sid))插入一个学生对象,会自动生成如下语句:ClassRoomc=newClassRoom();c.setCname(computer001);Studentss=newStudents(zhangsan);s.setClassroom(c);session.save(s);tx.commit();ViewCodeHibernate:insertintoClassRoom(cname)values(?)Hibernate:insertintoStudents(cid,sname)values(?,?)插入成功:基于xml配置实现多对一单向外键关联hibernate-mappingclassname=net.nw.vo.fk.mto.ClassRoomtable=classroomidname=cidcolumn=cidtype=intgeneratorclass=native//idpropertyname=cnamecolumn=cnametype=string//class/hibernate-mappingViewCode一方(教室类)无需做任何多方的定义。只需要维护好自己的属性配置即可。而多方只需要加上many-to-onename=column=“/就ok。hibernate-mappingclassname=net.nw.vo.fk.mto.Studentstable=studentsidname=sidcolumn=sidtype=intgeneratorclass=native//idpropertyname=snamecolumn=snametype=string/many-to-onename=classroomcolumn=cid//class/hibernate-mappingViewCodehibernate.cfg.xml里加上mappingresource=net/nw/vo/fk/mto/ClassRoom.hbm.xml/mappingresource=net/nw/vo/fk/mto/Students.hbm.xml/ViewCode注意:如果没有设置级联ALL,那么需要在保存的时候先保存班级,在保存学生,否则出错:objectreferencesanunsavedtransientinstance-savethetransientinstancebeforeflushing:ClassRoomclassRoom=newClassRoom();classRoom.setCname(CS);Studentsstudents=newStudents(111);students.setClassroom(classRoom);session.save(classRoom);session.save(students);tx.commit();ViewCode小结:使用many-to-one元素进行多对一关联关系配置,name属性指定类的属性名,column属性指定库表字段名,class属性指定类属性类型(加上姓,即包名),not-null属性指定属性是否允许为空,cascade属性指定是否级联保存和更新:save-update、delete、all、none。一对多单向外键关联当类与类建立了关联,程序能很方便的从一个对象导航到另一个或一组与之关联的对象,有了student对象,就可以通过student对象得到这个学生所属的班级的信息——students.getClassroom();,对于班级对象,如果想要得到某个学生的信息,怎么办呢?这时候可以反过来控制,一方控制多方,下面进行一对多单向外键关联。简单说就是和之前多对一相反,之前是多方持有一方的引用,而一对多关联关系是一方持有多方的集合的引用,注意区别:这里是持有多方的集合。基于注解的配置:@OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY),@JoinColumn(name=),除了级联之外,还要设置一方为懒加载模式。且外键还是加在了多方学生表里,只不过控制权变了,之前多对一关联是多方学生持有班级外键,控制班级,现在一对多关联,表里还是多方学生持有班级一方的外键,只不过控制权交给了班级,让班级控制学生。不要混淆。importjavax.persistence.*;importjava.util.Set;//班级类是一方,一方持有多方的引用@EntitypublicclassClassRoo