hibernate单表继承的三种实现方式详解

多态是java的优势之一,这种常用的特性hibernate这种框架也做了一定的支持,这期我们就来探讨下,hibernate关于继承方面的实现:

首先说明hibernate对于继承有三种实现方式,也是按数据库中表继承的实现分类的,希望大家在看这篇文章是,去了解下关系数据库中的表继承的实现可能对于hibernate的继承以及对java的多态性会有很大的帮助和深入了解:

好,废话不多说,

继承和数据表的对应关系:



三种实现方式,:

   在设置继承结构的映射时,我们可以写三份配置文件,也可以写一份,一般是-份,三份需指定extends属性,
    一份时一般是写在父类的配置文件中
  discriminator-value属性:
			用于鉴别是哪个类的一个值,表示这个值就是这个类。
			如果不写,默认为类的全限定名。   
    继承有三种实现方式:一种是:所有子类和父类都保存在一张表中,通过一个元组鉴别三种类型:
    第二种是:三张表示,每个类都由一张表表示,使用标签joined-class,多了一个属性,子类引用父类的主键,作为自己的主键,保证属性的连接;
   		(重点):保存时子类时,会现在父类表中保存父类子类共有的属性,然后再子类自己的表中保存自己的属性
		这点一定要知道:
第三种是:每个子类都在数据库中对应一张表,父类声明为抽象类,无表对应,
		在配置文件中父类申明为抽象类,但在写父类javabean时,是不是抽象类都可以(属性abstract),
		但是在配置文件一定要声明为抽象类,由于父类不对应table,所以当abstract=true,不要写table,
		写了hibernate也会自动忽略
		这时父类的作用更像是为了减少重复声明的存在一样
	(重点:)	这时每个子类的表中都会保存父类的子类的所有属性
		注意子类使用union-subclass标签;

这里我们采用论坛的类的继承来说明hibernate继承的实现方式:

我们先写三个java类,和测试类,

父类Article子类Reply和子类Topic

Article:

<span style="font-size:18px;">package hibernate_extends3;

import java.util.Date;

public class Article {
	private Integer id;
	private String title;
	private String content;
	private Date posttime;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}

	public Date getPosttime() {
		return posttime;
	}
	public void setPosttime(Date posttime) {
		this.posttime = posttime;
	}
	@Override
	public String toString() {
		return "Article [id=" + id + ", title=" + title + ", content="
				+ content + ", posttime=" + posttime + "]";
	}

	
}</span><span style="font-size:32px;">
</span>
Topic:

package hibernate_extends3;



public class Topic extends Article {
	private Integer type;

	public Integer getType() {
		return type;
	}

	public void setType(Integer type) {
		this.type = type;
	}


	
	
	
}

Reply:

package hibernate_extends3;

public class Reply extends Article {
	private Integer floor;

	public Integer getFloor() {
		return floor;
	}

	public void setFloor(Integer floor) {
		this.floor = floor;
	}


	
}

测试类:

package hibernate_extends1;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App {
	static SessionFactory sessionFactory=null;
	static{
		//加载配置文件
		sessionFactory=new Configuration().configure().
				addClass(Article.class).
				buildSessionFactory();
	}
	/**
	 *测试保存
	 */
	@Test
	public void testSave(){
		Session session=sessionFactory.openSession();
		session.beginTransaction();
		//新建对象
		Article article=new Article();
		article.setTitle("我是文章");
		article.setContent("我是文章内容");
		Reply replay=new Reply();
		replay.setTitle("我是回复");
		replay.setContent("我是回复内容");
		replay.setFloor(1);
		Topic topic=new Topic();
		topic.setTitle("我是主题");
		topic.setContent("我是主题内容");
		topic.setType(1);
		session.save(article);
		session.save(replay);
		session.save(topic);
		session.getTransaction().commit();
		session.close();
	}
	
	/**
	 * 测试获取
	 * 测试时,别忘记了,存取的顺序,不然会搞混reply和topic,导致获取失败,
	 * 鄙人过于粗心,导致拜拜浪费了3个小时,检查了两份文本,3个小时啊,大家要引以为鉴啊
	 */
	@Test
	public void testGet(){
		Session session=sessionFactory.openSession();
		session.beginTransaction();
		//新建对象
	Article article=(Article) session.get(Article.class, 1);
		Topic topic=(Topic) session.get(Topic.class, 3);
		Reply replay=(Reply) session.get(Reply.class, 2);
		System.out.println(article);
		System.out.println(topic);
		System.out.println(replay);
		
		
		///
	System.out.println();
		Article article1=(Article) session.get(Article.class, 2);
		Article article2=(Article) session.get(Article.class, 3);
		System.out.println(article1);
		System.out.println(article2);
		session.getTransaction().commit();
		session.close();
	}
}



一种是:所有子类和父类都保存在一张表中,通过一个元组鉴别三种类型,:

<span style="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">
<!-- Generated 2016-4-5 16:43:03 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_extends1">
 <!--    在设置继承结构的映射时,我们可以写三份配置文件,也可以写一份,一般是一份,三份需指定extends属性,
    一份时一般是写在父类的配置文件中
    
    继承有三种实现方式:一种是:所有子类和父类都保存在一张表中,通过一个元组鉴别三种类型如下:
    discriminator-value属性:
			用于鉴别是哪个类的一个值,表示这个值就是这个类。
			如果不写,默认为类的全限定名。
     -->
    <class name="Article" table="article" discriminator-value="article">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>
        	<!-- 用于鉴别是什么类型的一个列 ,这里是指定鉴别元组的元组类型和名称-->
		<discriminator type="string" column="class_"></discriminator>
<!--         在设置字符串类型的值时建议指定长度,不然系统默认长度, -->
        <property name="title" type="string" length="40">
            <column name="title" />
        </property>
        <property name="content" type="text" length="1000">
            <column name="content" />
        </property>
        <property name="posttime" type="timestamp">
            <column name="posttime" />
        </property>
 <!--        子类Replay -->
        <subclass name="Reply" discriminator-value="Reply" >
            <property name="floor" type="int" column="floor"/>
        </subclass>
         <!--        子类Topic -->
        <subclass name="Topic" discriminator-value="Topic">
            <property name="type" type="int" column="type"></property>
        </subclass>
    </class>
</hibernate-mapping></span><span style="font-size:24px;font-weight: bold;">
</span>

第二种是:三张表示,每个类都由一张表表示,使用标签joined-class,多了一个属性,子类引用父类的主键,作为自己的主键,保证属性的连接;
    保存时子类时,会现在父类表中保存父类子类共有的属性,然后再子类自己的表中保存自己的属性
这点一定要知道:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-5 16:43:03 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_extends2">
 <!--    在设置继承结构的映射时,我们可以写三份配置文件,也可以写一份,一般是一份,三份需指定extends属性,
    一份时一般是写在父类的配置文件中
  discriminator-value属性:
			用于鉴别是哪个类的一个值,表示这个值就是这个类。
			如果不写,默认为类的全限定名。   
    继承有三种实现方式:一种是:所有子类和父类都保存在一张表中,通过一个元组鉴别三种类型:
    第二种是:三张表示,每个类都由一张表表示,使用标签joined-class,多了一个属性,子类引用父类的主键,作为自己的主键,保证属性的连接;
   		保存时子类时,会现在父类表中保存父类子类共有的属性,然后再子类自己的表中保存自己的属性
		这点一定要知道:
		具体实现如下:
     -->
    <class name="Article" table="article" >
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>
      
<!--         在设置字符串类型的值时建议指定长度,不然系统默认长度, -->
        <property name="title" type="string" length="40">
            <column name="title" />
        </property>
        <property name="content" type="text" length="1000">
            <column name="content" />
        </property>
        <property name="posttime" type="timestamp">
            <column name="posttime" />
        </property>
 <!--        子类Replay 
 使用标签joined-class,多了一个属性,子类引用父类的主键,作为自己的主键,保证属性的连接
 -->
       <joined-subclass name="Reply" table="reply">
            <key column="rid"></key>
           <property name="floor" type="int" column="type"></property>
       </joined-subclass>
       
       
         <!--        子类Topic 
         
         使用标签joined-class,多了一个属性,子类引用父类的主键,作为自己的主键,保证属性的连接
         -->
     <joined-subclass name="Topic" table="topic">
         <key column="tid"></key>
           <property name="type" type="int" column="type"></property>
       </joined-subclass>
    </class>
</hibernate-mapping>

第三种是:每个子类都在数据库中对应一张表,父类声明为抽象类,无表对应:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-4-5 16:43:03 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="hibernate_extends3">
 <!--    在设置继承结构的映射时,我们可以写三份配置文件,也可以写一份,一般是一份,三份需指定extends属性,
    一份时一般是写在父类的配置文件中
  discriminator-value属性:
			用于鉴别是哪个类的一个值,表示这个值就是这个类。
			如果不写,默认为类的全限定名。   
    继承有三种实现方式:一种是:所有子类和父类都保存在一张表中,通过一个元组鉴别三种类型:
    第二种是:三张表示,每个类都由一张表表示,使用标签joined-class,多了一个属性,子类引用父类的主键,作为自己的主键,保证属性的连接;
   		(重点):保存时子类时,会现在父类表中保存父类子类共有的属性,然后再子类自己的表中保存自己的属性
		这点一定要知道:
第三种是:每个子类都在数据库中对应一张表,父类声明为抽象类,无表对应,
		在配置文件中父类申明为抽象类,但在写父类javabean时,是不是抽象类都可以(属性abstract),
		但是在配置文件一定要声明为抽象类,由于父类不对应table,所以当abstract=true,不要写table,
		写了hibernate也会自动忽略
		这时父类的作用更像是为了减少重复声明的存在一样
	(重点:)	这时每个子类的表中都会保存父类的子类的所有属性
		注意子类使用union-subclass标签;
     -->
    <class name="Article" abstract="true">
        <id name="id" type="int">
            <column name="ID" />
       <!--     注意当父类为抽象类时,主键不可使用数据库自动生成,
           当使用每个具体类一张表的方式时,主键生成策略不能是identity。
				因为在整个继承结构中,主键值是不能重复的。 -->
            <generator class="assigned" />
        </id>
      
<!--         在设置字符串类型的值时建议指定长度,不然系统默认长度, -->
        <property name="title" type="string" length="40">
            <column name="title" />
        </property>
        <property name="content" type="text" length="1000">
            <column name="content" />
        </property>
        <property name="posttime" type="timestamp">
            <column name="posttime" />
        </property>
 <!--        子类Replay 
 使用标签union-subclass,将父类的属性连接到子类的表中
 -->
 <union-subclass name="Reply" table="reply">
     <property name="floor" column="floor" type="int"/>
 </union-subclass>
       
       
     <!--        子类Topic
 使用标签union-subclass,将父类的属性连接到子类的表中
 -->
     <union-subclass name="Topic" table="topic">
         <property name="type" type="int" column="type"></property>
     </union-subclass>
    </class>
</hibernate-mapping>



三种测试方式不太一样,注意事项,需要在理解的基础上,就会明白,唯一需要改变的就是第三种,注意父类是抽象类,大家可以尽情测试,了解hibernate


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值