Hibernate學習_016_繼承映射

在JAVA面向對象的世界裏,繼承關係描述了對象之間的所屬關係,Hibernate對於java的繼承關係也有一定的支持。

在Hibernate中實現繼承映射,有三種方式:

第一種:SINGLE_TABLE。(最常用的一種方式

這種方式,將所有子類的字段和父類字段全部放到一個表中,然後用一個區分字段(Discriminator value)來區分一條記錄倒地屬於那個類。

其優點是:三種方式中最簡單的一種,所有字段都在一個表中,查詢的時候,不用做表之間的關聯查詢,速度最快,查詢效率最高。

其缺點是:1:子類所屬的各個字段不可以加NOT NULL限制。2:如果一個子類存在大量數據字段,那一條記錄中,將會產生大量的Null字段,而且表結構會很大,所以在子類比較少,而且子類的字段數不是特別多的時候才考慮使用這種映射方式。

代碼示例:(注:本文所講三種映射,均已Person、Teacher、Student這三個類爲例,其中Teacher、Student均是Person的子類)

Person超類:(在這個繼承樹的超類中,我們指定映射方式爲SINGLE_TABLE,同時指明 數據表 對應的區分字段名叫“discriminator”,超類Person對應的此字段值叫做“person”)

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="discriminator",discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue(value="person")
public class Person{
	private int id;
	private String name;
	@Id
	@GeneratedValue
	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;
	}
}
子類Teacher:(子類Teacher只需要指明此子類在表中的區分字段是“teacher”即可)

@Entity
@DiscriminatorValue("teacher")
public class Teacher extends Person{
	private String title;
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
}
子類Student:(子類Student只需要指明此子類在表中的區分字段是“student”即可)

@Entity
@DiscriminatorValue("student")
public class Student extends Person {
	private int score;
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
}
運行測試代碼,查看生成的表結構,我們得到如下結果:
16:29:04,084 DEBUG SchemaExport:377 - 
    create table Person (
        discriminator varchar(31) not null,
        id integer not null auto_increment,
        name varchar(255),
        score integer,
        title varchar(255),
        primary key (id)
    )

第二種:TABLE_PER_CLASS

這種方式,就是每個類對應一張表。不論是超類還是子類,而且特別說明的是,各個子類表中存放從超類那裏繼承而來字段,也就是各個子類所對應的表的字段是完備的。

其優點是:層次分明、結構清晰

其缺點是:效率不高,存在表之間的關聯操作,而且,要有一個存放各個子類表的主鍵取值的一箇中間表(主鍵種子表)。各個子表中的主鍵值依次參照這個主鍵種子取值,所以,各個子表中的主鍵一般不會是連續的。

代碼示例:

Person:

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@TableGenerator(
		name="t_gen",
		table="t_gen_table",
		pkColumnName="pk",
		valueColumnName="pk_value",
		initialValue=1,
		allocationSize=1,
		pkColumnValue="now_key"
		)
public class Person{
	private int id;
	private String name;
	@Id
	@GeneratedValue(generator="t_gen",strategy=GenerationType.TABLE)
	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;
	}
}
在這個超類中,我們指點了關聯各個子表主鍵的主鍵種子表是t_gen_table,並且定義了此表的其他的詳細信息。在ID生成策略中我們通過strategy=GenerationType.TABLE來指定ID的生成策略。

Teacher、Student這兩個子類,我們就不在需要加入@DiscriminatorValue("XXXX")了,只需要加入@Entity註解即可。

運行代碼測試,查看建表語句如下所示:

15:56:50,349 DEBUG SchemaExport:377 - 
    create table Person (
        id integer not null,
        name varchar(255),
        primary key (id)
    )
15:56:50,460 DEBUG SchemaExport:377 - 
    create table Student (
        id integer not null,
        name varchar(255),
        score integer not null,
        primary key (id)
    )
15:56:50,526 DEBUG SchemaExport:377 - 
    create table Teacher (
        id integer not null,
        name varchar(255),
        title varchar(255),
        primary key (id)
    )
15:56:50,592 DEBUG SchemaExport:377 - 
    create table t_gen_table (
         pk varchar(255),
         pk_value integer 
    ) 
看這裏,生成了三張表,這三張表在存入數據的時候,ID都是從t_gen_table中去取的,而不可以是自動生成的。

第三種:JOINED

採用這種映射策略時,父類實例保存在父類表裏,而子類實例則由父類表和子類表共同存儲。因爲子類實例也是一個特殊的父類實例,因此必然包含了父類實例的屬性,於是將子類與父類共有的屬性保存在父類表中;而子類增加的屬性,則保存在子類表中。 在這種映射策略下,無須使用辨別者列,但需要爲每個子類映射共有主鍵。而且如果繼承樹的深度很深,那麼查詢一個子類實例時,可能需要跨越多個表,因爲子類的數據依次保存在其多個父類中。效率較低。

代碼示例:(只給出Person的代碼,Teacher、Student和上面的TABLE_PER_CLASS一模一樣)

Person:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Person{
	private int id;
	private String name;
	@Id
	@GeneratedValue
	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;
	}
}
測試輸出代碼:

16:26:28,730 DEBUG SchemaExport:377 - 
    create table Person (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )
16:26:28,789 DEBUG SchemaExport:377 - 
    create table Student (
        score integer not null,
        id integer not null,
        primary key (id)
    )
16:26:28,845 DEBUG SchemaExport:377 - 
    create table Teacher (
        title varchar(255),
        id integer not null,
        primary key (id)
    )
16:26:28,901 DEBUG SchemaExport:377 - 
    alter table Student 
        add index FKF3371A1B860C688C (id), 
        add constraint FKF3371A1B860C688C 
        foreign key (id) 
        references Person (id)
16:26:29,012 DEBUG SchemaExport:377 - 
    alter table Teacher 
        add index FKD6A63C2860C688C (id), 
        add constraint FKD6A63C2860C688C 
        foreign key (id) 
        references Person (id)
從輸出可以看到,Studnet、Teacher這兩個類均參照了Person的主鍵。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章