zoukankan      html  css  js  c++  java
  • 【Hibernate 5】继承映射配置及多态查询

    一、继承实现的三种策略

    1.1,单表继承。每棵类继承树使用一个表(table per class hierarchy) ——>本文主要介绍的继承策略

    类继承树对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:
    1,父类用普通的<class>标签定义,在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
    如:<discriminator column=”XXX” type=”string”/>
    2,子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:Subclass标签的name属性是子类的全路径名;在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值;Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。

    PS:唯一字段隔离,也就是所谓的type,通过type确定子类的类型,每条数据中包含了需要的所有信息字段


    1.2,每个具体类一个表(table per concrete class)(有一些限制)

    这种策略使用joined-subclass标签来定义子类。父类、子类,每个类都对应一张数据库表。在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。子类与父类,通过相同的主键值来关联。实现这种策略的时候,有如下步骤:
    1,父类用普通的<class>标签定义即可,父类不再需要定义discriminator字段
    2,子类用<joined-subclass>标签定义,在定义joined-subclass的时候,需要注意如下几点:Joined-subclass标签的name属性是子类的全路径名;Joined-subclass标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。如:<key column=”PARENT_KEY_ID”/>,这里的column,实际上就是父类的主键对应的映射字段名称。
    3,Joined-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当Joined-subclass标签的定义与class标签平行的时候,需要在Joined-subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在joined-subclass标签的内部。

    PS:表隔离,每个表中都只有属于自身对应的属性,如果要获取完整的数据,则需要通过外键联合查询


    1.3,具体表继承。每个子类一个表(table per subclass) 

    这种策略使用union-subclass标签来定义子类。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,joined-subclass定义的子类的表,只包含子类特有属性映射的字段)。实现这种策略的时候,有如下步骤:
    1,父类用普通<class>标签定义即可

    2,子类用<union-subclass>标签定义,在定义union-subclass的时候,需要注意如下几点:Union-subclass标签不再需要包含key标签(与joined-subclass不同);Union-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当Union-subclass标签的定义与class标签平行的时候,需要在Union-subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在Union-subclass标签的内部。这个时候,虽然在union-subclass里面定义的只有子类的属性,但是因为它继承了父类,所以,不需要定义其它的属性,在映射到数据库表的时候,依然包含了父类的所有属性的映射字段。

    PS:表隔离,与每个具体类不同的是,这种策略只会为每个具体的子类生成表单,而在每个表单里,既包含了父类的属性,又包含了自身的属性。当需要查询一条完整数据的时候,不需要联合外键!


    二、实例介绍继承映射

    2.1,建立实体类和映射

    Animal类:

    <span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;
    
    public class Animal {
    
    	private int id;
    	
    	private String name;
    	
    	private boolean sex;
    
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public boolean isSex() {
    		return sex;
    	}
    
    	public void setSex(boolean sex) {
    		this.sex = sex;
    	}
    }
    </span>

    Bird类:

    <span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;
    
    public class Bird extends Animal {
    
    	private int height;
    
    	public int getHeight() {
    		return height;
    	}
    
    	public void setHeight(int height) {
    		this.height = height;
    	}
    }
    </span>

    Pig类:

    <span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;
    
    public class Pig extends Animal {
    
    	private int weight;
    
    	public int getWeight() {
    		return weight;
    	}
    
    	public void setWeight(int weight) {
    		this.weight = weight;
    	}
    }
    </span>

    映射文件:

    <span style="font-family:KaiTi_GB2312;font-size:18px;"><?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.angel.hibernate.Animal" table="t_animal" lazy="false">
    		<id name="id">
    			<generator class="native" />
    		</id>
    		<!-- 加入鉴别标签,且必须放在id后面 -->
    		<discriminator column="type" type="string"/>
    		<property name="name" />
    		<property name="sex" type="boolean" />
    
    		<subclass name="com.angel.hibernate.Pig" discriminator-value="P">
    			<property name="weight" />
    		</subclass>
    		<subclass name="com.angel.hibernate.Bird" discriminator-value="B">
    			<property name="height" />
    		</subclass>
    	</class>
    
    </hibernate-mapping> </span>

    2.2,测试类

    <span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;
    
    import org.hibernate.Session;
    
    import junit.framework.TestCase;
    
    public class test_extend extends TestCase {
    
    	public void testSave() {
    		Session session = null;
    		try {
    			// 创建session对象
    			session = HibernateUtils.getSession();
    			// 开启事务
    			session.beginTransaction();
    
    			Pig pig = new Pig();
    			pig.setName("daddy pig");
    			pig.setSex(true);
    			pig.setWeight(200);
    			session.save(pig);
    
    			Bird bird = new Bird();
    			bird.setName("mummy bird");
    			bird.setSex(true);
    			bird.setHeight(100);
    			session.save(bird);
    
    			session.getTransaction().commit();
    		} catch (Exception e) {
    			e.printStackTrace();
    			session.getTransaction().rollback();
    		} finally {
    			HibernateUtils.closeSession(session);
    		}
    	}
    	
    	public void testLoad(){
    		Session session=null;
    		try {
    			session = HibernateUtils.getSession();
    			session.beginTransaction();
    			Animal a = (Animal)session.load(Animal.class, 1);
    			//load默认支持lazy,所以我们看到的是Animal的代理,采用instanceof无法鉴别出真正的类型Pig
    			//如果想要load支持多态查询,则需要将lazy值设置为false
    			if (a instanceof Pig) {
    				System.out.println(a.getName());
    			}else {
    				System.out.println("不是猪!");
    			}
    			session.getTransaction().commit();
    		} catch (Exception e) {
    			e.printStackTrace();
    			session.getTransaction().rollback();
    		}finally {
    			HibernateUtils.closeSession(session);
    		}
    	}
    	
    }
    </span>

    三、多态查询

    多态查询:hibernate在加载数据的时候,能够采用instancof鉴别出其真正的类型

    在Hibernate中,支持多台查询的有:get、Hql。而对于load,因为其默认支持延迟加载lazy,所以它不支持多态查询,返回的只是一个代理值。如果想要让load支持多态查询,则需要在配置文件中将其lazy属性设置为false。


    四、总结

    继承映射在实际运用中还是很广泛中,在做这个例子的时候,突然想起来多租户数据隔离的三个策略,其实跟这个差不多。额,说明我脑袋里还是装东西了嘛。然后对于继承映射的三种策略,可以看出的是,单表继承是比较简单而且效率高的,只需要维护一个表。而具体表策略则需要进行外键维护等,相对来说单表继承是一个比较好的选择!

  • 相关阅读:
    Maven入门详解
    (二)从分布式一致性谈到CAP理论、BASE理论
    (一)从集中式到分布式
    四种MySQL存储引擎
    日期函数、时间函数总结(MySQL 5.X)
    SQL函数说明大全
    Java虚拟机1:什么是Java
    Java设计模式1:设计模式概论
    Linux概述
    Android 使用SharedPreference来进行软件配置的存取
  • 原文地址:https://www.cnblogs.com/hhx626/p/6010316.html
Copyright © 2011-2022 走看看