多态是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