Hibernate支持的三种数据库继承映射关系

1、subclass方式

将继承树的所有实例保存在同一个表内,在这个表内增加一个discriminator类来区别某一实例到底是哪一个类的实例

这个思想相当于把好几张表放在了一起,其原因是这几张表有很多的共同属性(子类从父类继承而来的属性)

这种做法的优势是,在查询表时(逻辑意义上的连接查询时),实际上数据库只在一张表内进行查询,无需进行多表连接查询,也无需进行union查询,因此性能比较好

这种做法的劣势也是很明显的,那就是在一定程度上破坏了数据库的清晰界限(本来是在多个表里的东西搞到了一张表里存),分表存是因为不同事物之间有差异属性,所以你把不同事物合一起存了,毕竟造成表中存储了很多的null元素(因为某一元素本应只对应几个列而不是全部列),并且所有子类定义的字段不能有非空约束,因为如果这些字段加入非空约束,那么父类的实例在这些列根本没有值,这肯定引起数据完整性冲突,导致父类的实例无法保存到数据库。

所以subclass方式实际是相当与用数据冗余和一些对数据库约束的设置的不方便(我们不能清晰的对每一个有独立逻辑意义的表进行单独的数据约束设置),来换取了查询效率的提高

2、joined-subclass方式

这种思想类似于我们学习数据库时的做法(至少是我的做法):在处理ISA关系时,将子类新增的关系存在新的表中,并在新的表中设置对于父类的外键约束

这种做法,与我在数据库上学到的知识完全相符,所以用起来也十分顺手,各种数据库相关设计,就与数据库上讲的各种相关设计一样,毫无违和感

当然这种做法也有一个缺点,是我们在数据库课程上较少考虑的,那就是查询效率的问题。在这种做法下,当程序查询子类实例时,需要跨越多个表查询,到底需要跨越多少个表,取决于该子类有多少层父类。正因为这个原因,所以joined-subclass继承映射策略对查询性能有一定的影响

3、union-subclass方式

这种思想是最有意思的,也是笔者写下这篇文章的核心原因。在这种做法下,子表和父表完全没有什么约束关系,子表存子表的,父表存父表的,看起来两者相互独立,只不过子类的属性囊括了父类的属性而已。

在这种方式下,子表和父表的联系是通过一个很巧妙的方式建立的,那就是子类和父类共享一个主键,这种思想说起来比较抽象,举个例子就是,假设有Person、Teacher、Student三个类,Person是父类,Teacher、Student继承自Person,这时这三个类在数据库中占有三个表,每个表只包含自己应有的属性,但他们三个表至少有一个共同属性id,为主键,这个主键是共享的如果Person中有一个id为1的元素,Teacher、Student中就不能再有id为1的元素了。

于是就通过这个主键把这三个表联系起来了,其实这时Person表已经不像Teacher、Student表的父类了,而更像是有一个抽象的父类存在,而Person、Teacher、Student都是这个父类的平行子类一样,当进行每一个子类的相关任务时,只需要处理相应的一张表就行,只有当处理对象是那个虚拟的父表时(并不是Person表),才会进行三个表的连接查询,这样既没有数据冗余,又不会很影响查询效率(对整体的查询总要少于对每一具体的查询吧(如果此项不成立,那说明我们子类的划分就很成问题了,也可能没什么意义了))

所以笔者觉得这个想法真的是很好的,是以前学数据库的时候从来没有想过的,所以一定要记下来,共享主键用一种抽象的,虚拟的,代价很小的方法解决了一个很大的问题。这种实现给人一种有点像C#中锯齿数组的感觉,妙极了

当然,使用union-subclass还需注意一下问题:1、如果一个属性在超类中进行了映射,其字段名必须与所有子类表中定义的相同2、由于同一类继承树中使用同一个主键种子,所以主键生成策略不能选用identity、sequence、native等策略