文档章节

Hibernate学习4--Hibernte的映射关系(二)

zimingforever
 zimingforever
发布于 2014/04/20 21:11
字数 2426
阅读 87
收藏 5

上一节我们主要研究下了Hibernate中的一一映射和多对一映射,这节我们看下Hibernate中的其他几种映射,包括一对多映射,多对多映射,复合主键映射及继承映射。

第一种是一对多映射,“一对多”,顾名思义,是由“一”的一端加载“多”的一端,关系交由“一”来维护。反映在Java代码中就是在“一”的一端中持有“多”一端的集合,而hibernate把这种关系反映到数据库的策略是在“多”一端的表上加上一个外键指向“一”一端表。显现,其实这采用的还是“多対一”的映射原理。 但是,在“一”一端维护关系是我们不提倡的,因为它有不可避免的缺点,即级联插入数据的时候要先插“多”一端,这样造成了两方面的不妥:1.如果我们把“多”一端的外键必须添加非空约束,将导致数据不能插入;2.即使外键不设置为非空,在插入“多”一端数据时外键将暂时为空( 因为此时它所引用的“一”记录还没有插入),而只有等到它所引用的“一”记录插入后,再发出update语句修改外键,这样的效率必然降低。这里我们用class和student举例。

 <class name="com.xiaoming.test.hibernate.classTest.Classes" table="classes2">
        <id name="id" length="4">
            <generator class="native"></generator>
        </id>
        <property name="name" length="10"></property>
        <set name="students" cascade="save-update">
            <key column="class_id"></key>
            <one-to-many class="com.xiaoming.test.hibernate.classTest.Student"/>
        </set>
    </class>

 key的含义,指在另一端增加的外键指向本主键.如果设置上属性not-null="true",表示该外键非空,则在由"一"的一端维护关系时,可能导致插入数据异常PropertyValueException.

one-to-many含义,指出set集合中的元素类型,以供加载时使用

set标签后面还可以加上inverse=ture属性,inverse="true"含义,把关联关系交由对方一端维护,而在操作本方数据时不再维护关系

 <class name="com.xiaoming.test.hibernate.classTest.Student" table="student2">
        <id name="id" length="4">
            <generator class="native"></generator>
        </id>
        <property name="name" length="10"></property>
        <many-to-one name="classes" column="class_id" cascade="save-update"></many-to-one>
    </class>

测试方法如下:

Student student1=new Student();    
student1.setName("奇隆"); 
Student student2=new Student();    
student2.setName("有朋"); 
Set<Student> students=new HashSet<Student>(); 
students.add(student1);    
students.add(student2); 

Classes classes=new Classes();    
classes.setName("不一班"); 
classes.setStudents(students); 
session.save(classes);

这种情况下如果没有配置cascade属性的话,存储class不成功,因为class对象引用了student对象student1和student2。

Student student1=new Student(); 
student1.setName("奇隆"); 
        session.save(student1);
        Student student2=new Student(); 
        student2.setName("有朋");    
        session.save(student2); 
        Set<Student> students=new HashSet<Student>(); 
        students.add(student1); 
        students.add(student2); 
        Classes classes=new Classes(); 
        classes.setName("不一班"); 
        classes.setStudents(students); 
         session.save(classes);

执行ok,有两种情况,一种是<set>标签中没有inverse="true。会先执行3条insert语句,分别插入student1和student2对象及class对象,但是此时student对象的classid为空,所以在执行完insert语句后还会执行对应的update语句来更新对应的student中对应的classid,对应语句如下:

Hibernate: insert into calss(name, id) values (?, ?) 

Hibernate: insert into student(name, id) values (?, ?) 
Hibernate: insert into student (name, id) values (?, ?) 
Hibernate: update student set class_id=? where id=? 
Hibernate: update sstudent set class_id=? where id=? 

如果set标签中有inverse=true的时候,表示把关系交给对方来维护,自己不负责维护相应的操作。存储过程是这样的:存classes时,由于有cascade="save-update",它会先触发存储student;    而在存储student时,inverse="true"指明了由它来维护关联关系,所以他要先存主表class,再回来存副表student 

所以对应的sql如下:

Hibernate: insert into sxt_hibernate_class (name, id) values (?, ?) 
Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?) 
Hibernate: insert into sxt_hibernate_student (name, class_id, id) values (?, ?, ?)  

 相应的读取代码如下:

  Classes classes = (Classes) session.load(Classes.class, 3); 
  System.out.println(classes); 
  Set<Student> students = classes.getStudents(); 
  for (Iterator<Student> stus = students.iterator(); stus.hasNext();) { 
        System.out.println(stus.next()); 
  }


接下来我们要研究的是多对多的映射,多对多常常用中间表来解决相互的关系,这样我们就要使用中间表或中间类来解决。中间类就是把我们的中间表抽象生成一个实体类,在映射的时候分别和两个关联类构成一对多的关系,即演变成两个一对多来处理。这里我们用role和player的对象来说明一下多对多的使用.

  <class name="com.xiaoming.test.hibernate.roleTest.Player" table="t_player">
        <id name="id" length="4">
            <generator class="native"></generator>
        </id>
        <property name="name" length="10"></property> 
        <set name="roles" table="t_player_role" cascade="save-update">
            <key column="playerid"></key>
            <many-to-many class="com.xiaoming.test.hibernate.roleTest.Role" column="roleid"></many-to-many>
        </set>
    </class>

table属性的含义,用来指定中间表 ,set中的key column属性含义,指定中间表中用来指向本表的外键 

     <class name="com.xiaoming.test.hibernate.roleTest.Role" table="t_role">
        <id name="id" length="4">
            <generator class="native"></generator>
        </id>
        <property name="name" length="10"></property>
        <set name="players" table="t_player_role" cascade="save-update">
            <key column="roleid"></key>
            <many-to-many class="com.xiaoming.test.hibernate.roleTest.Player" column="playerid"></many-to-many>
        </set>
    </class>

测试代码如下:

Role role1=new Role(); 
      role1.setName("后卫");  
      Role role2=new Role(); 
      role2.setName("前锋"); 
      Role role3=new Role(); 
      role3.setName("中锋"); 
      Player player1=new Player(); 
      player1.setName("姚明"); 
      Set<Role> roles1=new HashSet<Role>(); 
      roles1.add(role3); 
      player1.setRoles(roles1);   
      Player player2=new Player(); 
      player2.setName("詹姆斯"); 
      Set<Role> roles2=new HashSet<Role>(); 
      roles2.add(role1); 
      roles2.add(role2); 
      roles2.add(role3); 
      player2.setRoles(roles2); 
 
      session.save(player1); 
      session.save(player2);*/

   这个代码可以正确执行,每次保存play的时候都能级联保存对应的role和相关的关系表数据。 

另一种使用方法如下:

   Player player1=new Player(); 
      player1.setName("姚明");   
      Player player2=new Player(); 
      player2.setName("詹姆斯"); 
      Player player3=new Player(); 
      player3.setName("科比");  
      Role role1=new Role(); 
      role1.setName("中锋"); 
      Set<Player> players1=new HashSet<Player>(); 
      players1.add(player1); 
      players1.add(player2); 
      role1.setPlayers(players1);   
      Role role2=new Role(); 
      role2.setName("后卫"); 
      Set<Player> players2=new HashSet<Player>(); 
      players2.add(player2); 
      players2.add(player3); 
      role2.setPlayers(players2);   
      session.save(role1); 
      session.save(role2);*/

是通过role的维度来插入对应的player。

加载代码如下:

  Player player=(Player)session.load(Player.class, 1); 
      System.out.println(player); 
      for(Iterator<Role> iterator=player.getRoles().iterator();iterator.hasNext();){ 
        System.out.println(iterator.next()); 
      }

接下来是符合主键的映射,使用了composite-id标签,对应到一个符合主键类。这里我们用department来说明符合主键使用,department的area和name为其复合主键,对应的配置如下:

 <class name="com.xiaoming.test.hibernate.departmentTest.Department" table="department">
        <!-- 联合主键 -->
        <composite-id name="departmentPK">
            <key-property name="area" />
            <key-property name="name" />
        </composite-id>
        <property name="empCount" length="4" />
        <property name="birthday" type="date" />
    </class>

其中departmentPk是复合主键类,对应的测试代码如下:

   //插入数据
   Department dept = new Department();
        /** 生成主键对象 */
        DepartmentPK deptPK = new DepartmentPK();
        deptPK.setArea("area1");
        deptPK.setName("dept1");
        dept.setDepartmentPK(deptPK);
        dept.setEmpCount(100);
        dept.setBirthday(new Date());
        session.save(dept);
        
    //读取数据
     DepartmentPK deptPK = new DepartmentPK();
        deptPK.setArea("area1");
        deptPK.setName("dept1");
        Department dept=(Department)session.load(Department.class, deptPK);
        System.out.println(dept.getDepartmentPK().getArea()+","+dept.getEmpCount());
        
    //更新数据
    DepartmentPK deptPK = new DepartmentPK();
        deptPK.setArea("area1");
        deptPK.setName("dept1");
        Department emp=(Department)session.load(Department.class, deptPK);
        System.out.println(emp.getDepartmentPK().getArea()+","+emp.getDepartmentPK().getName()+","+emp.getEmpCount()+","+emp.getBirthday());
        emp.setEmpCount(100);
        session.saveOrUpdate(emp);


        DepartmentPK deptPK2 = new DepartmentPK();
        deptPK2.setArea("area1");
        deptPK2.setName("dept1");
        Department dept=(Department)session.load(Department.class, deptPK2);
        System.out.println(dept.getDepartmentPK().getArea()+","+dept.getDepartmentPK().getName()+","+dept.getEmpCount()+","+dept.getBirthday());

在映射关系中我们经常用到的两个属性有invere和cascade。cascade定义的是源头的对象插入或删除对象时,级联的关系对象也会做相关的操作。inverse属性对于多对多中带有关系表的时候会讲对关系表的操作放到另一方去操作。简单的说cascade是一种级联的程度,而invers表示的是是否维持两个实体的关系(外键)

在Hibernte中还有一种映射是继承映射,继承也分3种,

1 单表继承:每颗类继承树使用一个表(table per class hlerarchy) 
2 具体表继承:每个子类一个表(table per subclass) 
3 类表继承:每个具体类一个表(table per concrete class)

假设我们有基本类animal属性有id,name和sex,其子类bird,有属性height,子类pig有属性weight

对于第一种情况,多个类信息存储在一张表中,可能由表中的一个字段来标注具体是哪个子类,相应的配置如下:

<class name="Animal" table="t_animal" lazy="false">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <discriminator column="type" type="string"/>  
        <property name="name"/>  
        <property name="sex"/>  
        <subclass name="Pig" discriminator-value="P">  
            <property name="weight"/>  
        </subclass>  
        <subclass name="Bird" discriminator-value="B">  
            <property name="height"/>  
        </subclass>  
</class>

其中,父类使用discriminator来指定区分不同子类的字段,子类使用discriminator-value来表名本子类的discriminator字段。

对于第二种情况,这种策略是使用joined-subclass标签来定义子类的。父类、子类,每个类都对应一张数据库表。 在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中, 这个表只定义了子类中所特有的属性映射的字段。子类与父类,通过相同的主键值来关联。其配置关系如下:

<class name="Animal" table="t_animal">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<property name="sex"/>
		<joined-subclass name="Pig" table="t_pig">
			<key column="pid"/>
			<property name="weight"/>
		</joined-subclass>
		<joined-subclass name="Bird" table="t_bird">
			<key column="bid"/>
			<property name="height"/>
		</joined-subclass>
</class>

其中,join-subclass标签的name属性是子类的全路径名,key标签用来执行子类和父类是通过哪个字段关联的。

对于第3中情况,这种策略是使用union-subclass标签来定义子类的。每个子类对应一张表,而且这个表的信息是完备的, 即包含了所有从父类继承下来的属性映射的字段,相关的配置如下:

<class name="Animal" abstract="true">
		<id name="id">
			<generator class="assigned"/>
		</id>
		<property name="name"/>
		<property name="sex"/>
		<union-subclass name="Pig" table="t_pig">
			<property name="weight"/>
		</union-subclass>
		<union-subclass name="Bird" table="t_bird">
			<property name="height"/>
		</union-subclass>
</class>

这里unionclass不需要再包含key属性了。另外class中的abstracet属性如果为true的话则不会生成表结构,如果为false会生成表结构,但是不会插入数据。

总结一下,这里主要介绍了多对一,多对多的级联关系,还有其他的如复合主键映射和继承映射的关系。下一节将学习的是Hibernate中最强大的Hql部分。


© 著作权归作者所有

zimingforever
粉丝 142
博文 266
码字总数 315040
作品 0
杭州
程序员
私信 提问
Hibernate学习1--SpringMVC+Hibernate集成环境搭建

除了刚毕业那会用了几个月的hibernate好像好久都没有碰过了,正好最近在整理以前的学习笔记就把这块知识系统的学习一下,特别是hibernate和ibatis的对比应该对我现在做的东西有很大的帮助。 ...

王小明123
2014/04/03
2.7K
0
Hibernate学习3--Hibernte的映射关系(基础概念篇)

前两节我们分别从Hibernate的demo和Hibernate的概念上熟悉了Hibernate的使用,这一节我们来了解Hibernate中的映射关系 首先我们了解下Hibernate映射文件中的各种标签的用法 1<hibernate-mapp...

王小明123
2014/04/14
367
0
iBatis和Hibernate浅析

iBatis和Hibernate浅析 Hibernate Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hiber...

JAVA__
2012/08/16
158
1
Hibernate学习4--Hibernte的映射关系(一)

Hibernate中最绕的部分莫过于各种映射了,其实大致上就3种,一对一映射onetoone,一对多映射onetomany,多对一映射manytoone,多对多映射manytomany。一对一映射又有一对一主键映射和唯一外键...

王小明123
2014/04/18
107
0
IBatis和Hibernate区别

原文出处:http://www.cnblogs.com/mingyongcheng/p/3588100.html IBatis和Hibernate区别 1. 简介 Hibernate是当前最流行的O/R mapping框架。它出身于sf.net,现在已经成为Jboss的一部分了。...

ponpon_
2014/06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二)

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二) List 类型的操作 1、 向列表左侧添加数据 Long leftPush = redisTemplate.opsForList().leftPush("name", name); 2、 向列表右......

TcWong
今天
7
0
排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
昨天
4
0
mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
昨天
10
0
golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架...

非正式解决方案
昨天
9
0
前端——使用base64编码在页面嵌入图片

因为页面中插入一个图片都要写明图片的路径——相对路径或者绝对路径。而除了具体的网站图片的图片地址,如果是在自己电脑文件夹里的图片,当我们的HTML文件在别人电脑上打开的时候图片则由于...

被毒打的程序猿
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部