一、继承映射
继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种继承关系其实可以看做是一种枚举关系,一种类型中可以枚举出很多子类型,这些子类型和父对象形成了继承关系,能够对其进行枚举的大部分都可以看做是一种继承映射,所以这种枚举关系可以看做是继承映射,例如动物就是一种抽象类,它是其它动物猪、猫等的父类,它们之间就是一种继承关系,如下图:
这种继承映射在转化为关系模型后会生成一张表,那么这张表是如何区分这两种类型的呢?用的是关系字段,需要在表中添加类型字段,使用关键字来标明对象的类型。所以上图中的对象模型对应的表结构如下:
1.1、类文件
类文件中没有需要注意的地方,在编写时注意之间的继承关系即可。清单一:Animal类代码,只需要添加基本的属性。
- package com.src.hibernate;
- public class Animal {
- //id号
- private int id;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- //名称
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- //性别
- private boolean sex;
- public boolean isSex() {
- return sex;
- }
- public void setSex(boolean sex) {
- this.sex = sex;
- }
- }
清单二:Bird和Pig类,添加基本的属性,并继承Animal类。
- package com.src.hibernate;
- public class Bird extends Animal {
- //高度
- private int height;
- public int getHeight() {
- return height;
- }
- public void setHeight(int height) {
- this.height = height;
- }
- }
- package com.src.hibernate;
- public class Pig extends Animal {
- //重量
- private int weight;
- public int getWeight() {
- return weight;
- }
- public void setWeight(int weight) {
- this.weight = weight;
- }
- }
1.2、映射文件
映射文件中需要添加对应的映射,该模型中只需要添加一个映射文件,因为只生成一张表,在映射文件中添加对应的子类映射,使用<subclass>标签,标签中添加鉴别器discriminator-value,该鉴别器属性指明了在数据库中写入数据时指示写入的是何种类型,如下:- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.src.hibernate.Animal" table="t_animal">
- <id name="id">
- <generator class="native"/>
- </id>
- <!-- 加入鉴别标签,且必须放在id后面 -->
- <discriminator column="type" />
- <property name="name"/>
- <property name="sex" type="boolean"/>
- <subclass name="com.src.hibernate.Pig" discriminator-value="P">
- <property name="weight"/>
- </subclass>
- <subclass name="com.src.hibernate.Bird" discriminator-value="B">
- <property name="height"/>
- </subclass>
- </class>
- </hibernate-mapping>
1.3、分析结果
生成的mysql数据库表中不仅会添加Animal的基本属性,而且会添加Pig和Bird的属性,因为在映射文件中使用<subclass>写出了所添加的属性,另外还添加了相应的鉴别器属性,所以在数据库中会添加对应的鉴别列,生成的表结构如下图:
二、数据操作
2.1 写入数据
在进行数据读取和写入操作时需要注意类中的操作使用了- public void testSave(){
- Session session=null;
- try{
- //创建session对象
- session=HibernateUtils.getSession();
- //开启事务
- session.beginTransaction();
- Pig pig=new Pig();
- pig.setName("小猪猪");
- pig.setSex(true);
- pig.setWeight(200);
- session.save(pig);
- Bird bird=new Bird();
- bird.setName("xiaoniaoniao");
- bird.setSex(true);
- bird.setHeight(100);
- session.save(bird);
- session.getTransaction().commit();
- }catch(Exception e){
- e.printStackTrace();
- session.getTransaction().rollback();
- }finally{
- HibernateUtils.closeSession(session);
- }
- }
2.2 多态查询--get和hql
Note:多态查询不支持延迟加载,也就是说如果使用load方法,需要在映射文件中将延迟加载设置为false。
2.2.1 load延迟加载
load支持延迟加载,在加载对象时其实生成的是对象的代理,所以在使用多态查询时需要在映射文件中将延迟加载设置为false,如下:- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.src.hibernate.Animal" table="t_animal" lazy="false">
- <id name="id">
- <generator class="native"/>
- </id>
- <!-- 加入鉴别标签,且必须放在id后面 -->
- <discriminator column="type" />
- <property name="name"/>
- <property name="sex" type="boolean"/>
- <subclass name="com.src.hibernate.Pig" discriminator-value="P">
- <property name="weight"/>
- </subclass>
- <subclass name="com.src.hibernate.Bird" discriminator-value="B">
- <property name="height"/>
- </subclass>
- </class>
- </hibernate-mapping>
load加载方法,使用load加载该示例中支持多态查询,在配置文件中将延迟加载设置为false,所以这里使用load方法能够加载获得相应的对象类。
- public void testLoad(){
- Session session=null;
- try{
- session=HibernateUtils.getSession();
- session.beginTransaction();
- Animal ani=(Animal)session.load(Animal.class,1);
- System.out.println(ani.getName());
- //因为load默认支持lazy,所以我们看到的是Animal的代理
- //所以采用了instanceof无法鉴别出真正的类型Pig
- //所以load在此情况下是不支持多态查询的
- if(ani instanceof Pig){
- System.out.println("我是小猪猪!");
- }else{
- System.out.println("我不是小猪猪!");
- }
- session.getTransaction().commit();
- }catch(Exception e){
- e.printStackTrace();
- session.getTransaction().rollback();
- }finally{
- HibernateUtils.closeSession(session);
- }
- }
2.2.2 hql查询
hql支持多态查询,这主要由于查询出的是一个真正的对象,并不会返回一个代理,所以hql支持多态查询,另外在查询时需要注意查询语句中不要使用表名,而是要使用类名称,Hibernate会根据类名称将其映射为对应的表名称,如下:- public void testLoad5(){
- Session session=null;
- try{
- session=HibernateUtils.getSession();
- session.beginTransaction();
- List<Animal> list=session.createQuery("from Animal").list();
- for(Iterator iter=list.iterator();iter.hasNext();){
- Animal a=(Animal)iter.next();
- if(a instanceof Pig){
- System.out.println("我是小猪猪!");
- }else{
- System.out.println("我不是小猪猪!");
- }
- }
- session.getTransaction().commit();
- }catch(Exception e){
- e.printStackTrace();
- session.getTransaction().rollback();
- }finally{
- HibernateUtils.closeSession(session);
- }
- }
查询结果:
- Hibernate: select animal0_.id as id0_, animal0_.name as name0_, animal0_.sex as sex0_, animal0_.weight as weight0_, animal0_.height as height0_, animal0_.type as type0_ from t_animal animal0_
- 我是小猪猪!
- 我不是小猪猪!
- 我是小猪猪!
- 我不是小猪猪!
结语
继承映射是对象模型中重要的关系映射,通过使用继承映射能够将继承关系转换为对应的关系表,在配置映射文件时需要使用<subclass>标签,另外还需要在标签中添加鉴别器属性来标明不同的类型,在操作读取时才能很快的鉴别出相应的类型。