一对多关联映射学习总结——hibernate
- 格式:pdf
- 大小:111.14 KB
- 文档页数:6
hibernate一对多关联映射一对多关联映射映射原理一对多关联映射和多对一关联映射的映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。
关联关系都是由多端维护,只是在写映射时发生了变化。
多对一和一对多的区别多对一和一对多的区别在于维护的关系不同:(1)多对一:多端维护一端的关系,在加载多端时,可以将一端加载上来。
(2)一对多:一端维护多端的关系,在加载一端时,可以将多端加载上来。
分类一对多单向关联映射对象模型从对象模型中,我们可以看出,Group持有User的一个引用。
由于是单向关联,所以数据在加载Group时,会把User 加载上来,但是User并不知道Group的存在。
我们先看一下Group和User的实体,以及映射文件。
GroupUserUser.hbm.xmlGroup.hbm.xml生成的表结构和测试数据缺点1)因为多端User不知道Group的存在(也就是User不维护与Group的关系),所以在保存User时,关系字段groupId 为null,如果该字段设置为非空,则将无法保存数据。
2)因为User不维护关系,而Group维护关系,Group就会发出多余的update语句,保证Group和User有关系,这样加载Group时才把该Users对应的用户加载上来。
一对多双向关联映射对象模型双向关联映射对比单向关联映射,对象的加载方向由单向变成了双向。
我们看一下Group和User的实体,映射文件GroupUserGroup.hbm.xmlUser.hbm.xml生成的表和测试数据一对多双向关联的映射方式:1)在一的一端的集合上采用<key>标签,在多的一端加入一个外键2)在多的一端采用<many-to-one>标签注意:<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱。
inverse属性:inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为false表示本端维护关系,如果inverse 为true,则本端不能维护关系,会交给另一端维护关系,本端失效。
hibernate一对多关联映射—单向一、简述一对多关联映射(one-to-many)1、在对象模型中,一对多的关联关系,使用集合表示比如Classes(班级)和Student(学生)之间是一对多的关系public class Classes{private String id;private String name;private Set students;}public class Student{public String id;public String name;}2、我们以前学过学生对班级是多对一,返过来,班级对学生就是一对多。
3、我们多对一的关系是用户和组。
返过来看,从组这边来看,就是一对多了。
下面学生的示例是班级和学生。
和用户和组是一样的。
一个班级有多个学生,这是一对多的关系;返过来,多个学生属于一个班级,这就是多对一了。
4、建立对象模型5、这两个对象模型之间是有关系的。
我们现在讲的是一对多。
一的一端是班级。
多的一端是学生。
那么怎么样能体现出这种关系呢?我们在学习多对一时,是在多的一端加上一个字段。
这个字段做为外键关联一的一端。
多对一,就是我们在看到学生的时候,能够知道这个学生是哪个班级的。
或者是当我们看到用户的时候,知道这个用户是哪个组的。
所以在用户里面持有组的引用。
6、那么一对多,就是一个组里面有多少个用户。
所以要维护这种关系,必须在组里面持有用户的集合。
班级和学生也是一样的。
一个班级有多少学生,所以在班级里面要持有相应的学生的集合。
如下图我们用Set,通常用户Set做映射。
箭头表示两者之间是有关系的。
7、上面的是对象模型,那么这种模型要映射成什么样呢?当我们定义多对一的关系时,在加载多的一端时,能够把1的一端加载上来。
因为两者之间是有关系的。
同理,一对多也是一样的,它要维护这种关系。
这种关系就是一对多。
一的一端要指向多。
在维护这种关系时,在加载一的时候,就会把一的一端加载上来。
Hibernate实体关联关系映射----总结在我看来,Hibernate提供这些映射关系,常⽤就是⼀对⼀和多对⼀,并且在能不⽤连接表的时候尽量不要⽤连接表。
多对多会⽤到,如果⽤到了,应该⾸先考虑底层数据库设计是否合理。
在实际开发中,在Hibernate关联关系之外常常还有另外⼀种选择⽅案,表各⾃作为单表映射,业务逻辑控制外键关系(有时候就是⼀个相关联的列,但不⼀定要加外键约束),这样更加灵活,并且数据的完整性同样有保证。
当然,“单表映射,业务控制外键关系”并不是说Hibernate的实体关联功能是多余的,Hibernate的实体关联的优点很多,随便拿本书都是讲优点,⽤好了会让开发⼈员感觉更⽅便,现在我也是两种⽅案结合使⽤。
⽐如对于不很确定的两个实体,常常选⽤单表关联。
以前在初学Hibernate还没有完全搞清楚这些关联关系的时候,就是⽤单表映射,业务控制外键关系做的,发现没有任何问题,程序同样运⾏得很好。
看了这些是不是后悔浪费时间学习映射关系了?呵呵,Hibernate的OR Mapping是Hibernate的灵魂,我相信Hibernate的创始⼈⽐我们⼀般⼈的理解更深刻。
只有学会了这些才能体会Hibernate设计者的思想。
学⼀个东西,不光⾃⼰写代码,还应该能看懂别⼈的代码才⾏。
因此系统学习这些关联映射还是⼤有必要的。
以上都是我⾃⼰的观点。
欢迎在此交流讨论。
Hibernate在实际项⽬开发中,hbm.xml包括数据库脚本都是通过Xdoclet⽣成的,在此不采⽤Xdoclet的⽬的是为了便于理解这些映射模型。
实体-数据表-映射⽂件三者对⽐看,太直观了。
瞌睡了,暂时先写到此,有新思路了再补上。
-----------------------------------------------------回Hibernate:Hibernate关联关系映射⽬录│├─单向关联│├─│├─│├─│├─│├─│├─│├─│└─└─双向关联├─├─├─├─├─└─。
Hibernate(6)——一对多和多对多关联关系映射(xml和注解)总结涉及的知识点总结如下:∙One to Many 映射关系o多对一单向外键关联(XML/Annotation)o一对多单向外键关联(XML/Annotation)o懒加载和积极加载o一对多双向外键关联(XML/Annotation)∙Many to Many 映射关系o多对多单向外键关联(XML/Annotation)o多对多双向外键关联(XML/Annotation)o set的inverse元素详解∙问题小结∙关联关系的优缺点多对一单向外键关联关系注意多对一关联是多方持有一方的引用。
看一个例子,去淘宝购物,那么一个淘宝用户可以对应多个购物订单,如图所示:多的一方是Orders,持有一方的引用,也就是Users,而在Users中无需作任何定义,从订单到用户的关系是单向多对一关联。
对应数据库就是:还有比如说学生和班级的关系,多个学生可以属于同一个班级,这就是从学生到班级也是典型的单向多对一关系,看代码实现:基于注解的多对一单向外键关联:单向多对一关联中,多方需要持有一方的引用,那么多方(学生类)需要额外配置,需要对持有的一方引用使用注解@ManyToOne (cascade={CascadeType.ALL}, fetch=FetchType.EAGER),设置为级联操作和饥渴的抓取策略,@JoinColumn(name="cid"),而一方(教室类)无需做任何多方的定义。
注意;多方必须保留一个不带参数的构造器!import ;import ;import ;//班级类,在多对一关系中属于一的方,不持有其他多余的配置,反而是被多方持有public class ClassRoom {private int cid;//班级编号private String cname;//班级名称// 自动增长的主键@Id@GeneratedValuepublic int getCid() {return cid;}public void setCid(int cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {ame = cname;}}View Code一方——班级类无需做多余的定义,下面是多方——学生实体和配置:import ;import ;import ;import ;import ;import ;import ;//学生实体类,属于多对一的多方,持有班级(一方)的引用@Entitypublic class Students {private int sid; //编号private String sname; //姓名private ClassRoom classroom;//学生班级//注意:多方一定要显式的定义不带参数的构造方法public Students() {public Students(String sname){this.sname = sname;}// 多方使用注解:@ManyToOne// fetch=FetchType.EAGER,急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
框架学习之Hibernate 第六节关系映射学习各种映射关系时总结:①如何将对象之间的关联关系映射到数据库中②如何检索出关联对象 1.多对一映射它是用法最多的映射关系,性能上占有优势关系模型和对象模型:两者并不是一一对应的举个例子:告知员工属于哪个部门和告知部门有哪些员工对于数据库(关系模型)来说只要有一个就可以但是对于对象模型不是如此,告知员工属于哪个部门之后,部门并不会知道自己有哪些员工 2.一对多映射它的关系模型和上面一样,也就是表的结构并不转变,但是对象模型转变了 3.一对一映射主对象和从对象主对象假如没有从对象可以,但是从对象没有主对象是不可的查找主对象时只用了一条sql语句,用法了outer 查找从对象时用了两条语句,首先查从对象,然后查主对象(假如要用法从对象对应的主对象)两种映射办法:①基于主键的一对一②基于外键的一对一 4.多对多映射用法的不是无数,要注重数据量的大小对性能的影响,由于多对多需要查三张表 5. 组件映射当一个类的属性很特别,不是数据库中支持的类型,而且又算不上是一个实体,没有表与之对应时可以用法组件映射假如组件的属性不能和表中的字段容易对应的时候可以挑选用法自定义用户类型! 6.关系映射的总结①对于关联关系的查询,Hibernate普通都是用法两条sql语句将它查出来,但是一对一的状况里的查主对象例外,它是一条sql 7.集合映射xml – Java集合类型 - 特点 xml中需要配置的信息:- Set 没有重复,不保存加入的挨次array:- Class[] 有挨次的 list-indlist:- List 可以重复,有挨次的 list-indexbag:- List 不保存挨次的List list-indexmap:- Map map键值对的映射类型 map-key编写 xml 办法用法原则:多数状况下都是用法set,需要保证挨次用法list,但是想用List而又不需要保证挨次用法bag 注重点:①定义成 Set,而不是 HashSet②本来是 HashSet,保存了之后就不再是 HashSet 了,强制转型时会报错的!缘由是Hibernate举行的封装,变成了PersitentSet,实现了 Set 接口,但是和 HashSet 没有关系,不能第1页共2页。
Java程序员从笨鸟到菜鸟之(五十四)细谈Hibernate(五)Hibernate一对多关系映射前几篇系列博客:细谈Hibernate(一)hibernate基本概念和体系结构细谈Hibernate(二)开发第一个hibernate基本详解细谈Hibernate(三)Hibernate常用API详解及源码分析细谈Hibernate(四)Hibernate常用配置文件详解在前几篇博客,我们初步对Hibernate有了一定的基础性的认知了,也能够简单的用hibernate进行增删改查,但hibernate真正的难度和精髓我们都还没接触到,其中最主要的关联映射就是其中一个,这篇博客,我们就一起来看一下这个hibernate关联映射。
我们大家都知道,在域模型(实体域)中,关联关系是类与类之间最普遍的关系,他是指通过一个对象持有另一个对象的实例根据UML语言,关系是有方向的。
实质上关联映射的本质:将关联关系映射到数据库,所谓的关联关系是对象模型在内存中的一个或多个引用。
搞清关联映射的的关键就在于搞清实体之间的关系。
下面我们首先来看一下具体什么事关联关系:一:关联关系1.关联关系的方向可分为单向关联和双向关联。
单向关联:假设存在两张表person表和address表,如果在应用的业务逻辑中,仅需要每个person实例能够查询得到其对应的Address实例,而Address实例并不需要查询得到其对应的person 实例;或者反之。
双向关联:既需要每个person实例能够查询得到其对应的Address实例,Address实例也需要查询得到其对应的person实例。
2.关联的数量,根据拥有被关联对象的个数确定多对一(many to one):如用户和组学生和班级一对多(one to many):如用户和电子邮件多对多(many to many):如学生选课一对一(one to one):如用户和身份证下面我们就开始讲第一种关联关系:一对多,一对多总共分为:单向一对多,单向多对一,双向一对多。
一对多关联映射(one-to-many单向)一、对象模型在对象模型中一对多关联映射,通常在一的一端要使用集合来表示关联关系。
比如班级-->学生就是一个典型的一对多的关系。
说明:之所以在一的一端需要持有对多的一端集合引用,是为了方便在加载班级的时候同时加载对应班级下面的学生。
二、原理【实现原理】先有班级[one]后有学生[many],实现一对多需要在多的一端建立外键指向一的端one-to-many单向:就是能从Cleasses中访问到对应的学生,反之无效.三、面试题【面试题】多对一与一对多的区别与联系?一对多关联映射利用了多对一关联映射原理多对一关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是多指向一(Person---Group)一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多(Classes---Students)总结:也就是说一对多和多对一的映射策略是一样的,只是角度不同四、业务模型(实体类)ClassesPOJO.javaprivate int id;private String name;private Set students;//一指向多StudentPOJO.javaprivate int id;private String name;五、配置文件(1)一的一端(Classes.hbm.xml)的配置:需要加入<set>标签<set name="students(Classes实体类中Set接口类型的变量名)"><key column="classid(对应于多的一端在数据库中的外键)"/><one-to-many class="多的一端实体类的路径"></set><hibernate-mapping package="com.tarena.hibernate"><class name="Classes"table="t_classes"><id name="id"><generator class="native"/></id><property name="name"/><set name="students"><key column="classesid"/><one-to-many class="Student"/></set></class></hibernate-mapping>(2)多的一端(Student.hbm.xml)的配置:<hibernate-mapping><class name="com.bjsxt.tarena.Student"table="t_student"><id name="id"><generator class="native"/>//ID自动增长</id><property name="name"/></class></hibernate-mapping>六、代码测试(1)save操作()存储策略:因为在Classes实体类(One)中存在一个对Student实体类的Set集合引用,所以要先存Student 对象,然后在为Student分配班级。
public void testSave1(){Session session=null;try{session=HibernateUtils.getSession();session.beginTransaction();//创建学生1Student student1=new Student();student1.setName("张三");session.save(student1);//记得要先保存学生信息到数据库//创建学生2Student student2=new Student();student2.setName("李四");session.save(student2);//记得要先保存学生信息到数据库//将学生放入Classes实体的Set集合Set students=new HashSet();students.add(student1);students.add(student2);//创建学生对象并把学生集合在放入到班级对象中Classes classes=new Classes();classes.setName("sd0801");//为班级分配学生classes.setStudents(students);//保存班级对象的同时也把对应班级的学生存入数据库session.save(classes);session.getTransaction().commit();}catch(Exception e){e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}说明:(1)上面方法之所以可以正确保存学生对象,是因为t_students表中的外键classesid约束允许为空,假如此外键设置非空了将会插入数据库的时候报错。
(2)上面代码的插入数据库的流程:先存入学生对象(id自增,name程序设定,classesid为空),当创建完班级对象后,在象数据库存入班级信息的时候在同时把班级的id做为外键同时也为t_students表的classesid 存入对应班级的id(此时Hibernate会发出update语句),由此可得出结论:假如同时批量创建学生对象,然后为多个学生分配班级,此时hibernate会发出多个update语句去为t_students表外键classesid赋值,所以影像了程序的性能。
(2)Load操作(加载班级看对应班级的学生信息)public void testLoad1(){Session session=null;try{session=HibernateUtils.getSession();session.beginTransaction();//先加载班级Classes classes=(Classes)session.load(Classes.class,1);//打印班级名称System.out.println("="+classes.getName());//获取班级中的学生信息Set students=classes.getStudents();for(Iterator iter=students.iterator();iter.hasNext();){Student student=(Student)iter.next();System.out.println("="+student.getName());}session.getTransaction().commit();}catch(Exception e){e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}在一一端维护关系的缺点:*如果将t_student表里的classesid字段设置为非空,则无法保存*因为不是在student这一端维护关系,所以student不知道是哪个班的,所以需要发出多余的update语句来更新关系(所以建议采用下面的双向关联一对多)一对多关联映射(one-to-many双向(常用))一、如何实现一对多双向(实现原理)(1)在一的一端的实体类中加入对多的一端的Set接口引用如:private Set students;//一指向多(Set)(2)在多的一端的实体类中加入对一的一端的实体引用如:private Classes classid;//多指向一(vo)对象模型实例图如下:二、实体类映射的配置文件Classess.hb.xml:<hibernate-mapping><class name="shuangXiang.pojo.Classess"table="t_classes"><id name="id"column="id"type="ng.Integer"><generator class="native"/></id><set name="students"inverse="true"cascade="all"><!--对应Classes实体类中private Set students;--><key column="classid"/><!--对应于多的一端在数据库中的外键--><one-to-many class="shuangXiang.pojo.Student"/><!--多的一端实体类的路径--></set></class></hibernate-mapping>Student.hb.xml:<hibernate-mapping><class name="shuangXiang.pojo.Student"table="t_student"><id name="id"column="id"type="ng.Integer"><generator class="native"/></id><property name="name"column="name"type="ng.String"/><many-to-one name="classess"column="classid"></many-to-one><!--many-to-one会用name属性的值来生成一个外键指向一的一端,维护多对一的关系,但是在一对多双向关联的时候必须用column属性把name属性的值绑定在一起(此时classid对应于Classes.hbm.xml文件中<key column="classid"/>;)--></class></hibernate-mapping>三、代码测试/***双向关联的存储*/public void testSave02(){session=HibernateUtils.getSession();session.beginTransaction();//先创建好班级Classess classess=new Classess();classess.setName("0802");session.save(classess);//按需要给对应的学生分配班级Student student=new Student();student.setName("李四");student.setClassess(classess);session.save(student);session.getTransaction().commit();}/***双向关联查询*/public void testLoad(){Session session=HibernateUtils.getSession();Student stu=(Student)session.load(Student.class,4);System.out.println("单向获取的姓名:"+stu.getName());System.out.println("单向获取的班级:"+stu.getClassess().getName());Classess classes=(Classess)session.load(Classess.class,4);System.out.println("获取班级姓名:"+classes.getName());}四.相关总结(1)hihernate一对多关联映射(双向Classes<----->Student)(2)一对多双向关联映射:*在一一端的集合上使用<key>,在对方表中加入一个外键指向一一端*在多一端采用<many-to-one>注意:<key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段的错误如果在”一“一端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在多的一端来维护关联关系(3)关于inverse属性:inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,默认inverse为false,所以我们可以从”一“一端和”多“一端维护关联关系,如果设置成inverse为true,则我们只能从多一端来维护关联关系注意:inverse属性,只影响数据的存储,也就是持久化(4)inverse和cascade*inverse是关联关系的控制方向*cascade操作上的连锁反应。