通过前面几篇文章,介绍了关联映射的一些概念。在实际应用中,关联映射用到的最多。除此之外,还会较多的用到本文讲到的继承映射。
实现继承映射,主要有三种策略:单表继承、具体表继承和类表继承。
单表继承——每棵继承树使用一个表;
具体表继承——每一个类分别使用一个表;
类表继承——每个具体类分别使用一个表。
看下图集成结构:Pig和Bird都属于Animal,并且Pig和Bird都分别有自己特有的属性。分下使用三种继承映射对它进行实现。
继承映射无论采用三种策略中的哪一种,实体类均是一样的。子类继承父类Animal,并各自拥有各自的属性。这里不做过多介绍。
1、每棵继承树使用一张表的映射
此种映射方式,在数据库中,只生成一个表。此外,表中会多一个鉴别字段:
映射方式:
<?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 package="com.lzq.hibernate"> <class name="Animal" table="t_animal" lazy="true"> <id name="id"> <generator class="native" /> </id> <!-- 此处为在配置中加的鉴别字段,用于对Pig和Bird做出区分--> <discriminator column="type" type="string"/> <property name="name" /> <property name="sex" /> <!-- 当discriminator的值为P时,为Pig,特有属性为weight--> <subclass name="Pig" discriminator-value="P"> <property name="weight" /> </subclass> <!-- 当discriminator的值为P时,为Pig,特有属性为height--> <subclass name="Bird" discriminator-value="B"> <property name="height" /> </subclass> </class> </hibernate-mapping>
显然,该种策略,对少量数据的查询有着得天独厚的优势,只有一张表,节约查询时间,简单易行。而缺点就是存在冗余字段,而且面对大数据量,就会显得有些吃力。
2、每个类一张表使用一张表的映射
该种映射方式,映射的结果,有几个类,就会生成几个表。因此,在此例中会生成三个表:
映射方式:
<?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 package="com.lzq.hibernate"> <class name="Animal" table="t_animal"> <id name="id"> <generator class="native" /> </id> <property name="name" /> <property name="sex" /> <!-- 每个类使用一张表:每个<joined-subclass>标签生成一张表, <joined-subclass>标签下的<key>标签映射成主键,<property>映射成字段 --> <joined-subclass name="Pig" table="t_pig"> <key column="pid" /> <property name="weight" /> </joined-subclass> <!-- 同上--> <joined-subclass name="Bird" table="t_bird"> <key column="bid" /> <property name="height" /> </joined-subclass> </class> </hibernate-mapping>
该种映射方式不存在数据冗余,但是每次查询,最少查询两张表。
3、每个具体类一张表的映射
本例中存在两个具体类,即会映射成两张表:
映射方式:
<?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 package="com.lzq.hibernate"> <!-- 需要在class标签上设置abstract为true,不然会生成Animal表 --> <class name="Animal" table="t_animal" abstract="true"> <!-- 主键生成策略必须采用手动赋值的方式--> <id name="id"> <generator class="assigned" /> </id> <property name="name" /> <property name="sex" /> <!-- 每个具体类一张表:只有每个<union-subclass>标签会生成一张表有意义的表, <property>标签映射成特有字段 --> <union-subclass name="Pig" table="t_pig"> <property name="weight" /> </union-subclass> <!-- 同上--> <union-subclass name="Bird" table="t_bird"> <property name="height" /> </union-subclass> </class> </hibernate-mapping>
每个具体类一张表映射,不能采用自增的方式生成主键。原因就是增加一个Pig,然后在增加一个Bird的时候,可能出现重复主键。
总结一下:
每个继承树一张表优点是:查询速度快,效率高;缺点是:存在大量冗余,而且在查询的数据特别大时,不适合采用该种方式。
每个类一张表优点是:层次清楚,无冗余;缺点是:类的层次多,并且有一个类就需要有一个表,导致会产生很多表。而且,查询时关联的表太多,影响查询速度。
每个具体类一张表优点是:层次清楚,无冗余;缺点是:使用自增主键方式会产生重复逐渐。
总之,最好的方式就是根据具体情况,酌情选择。