Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 冬眠效率';s表每子类继承策略_Java_Hibernate_Database Design_Inheritance - Fatal编程技术网

Java 冬眠效率';s表每子类继承策略

Java 冬眠效率';s表每子类继承策略,java,hibernate,database-design,inheritance,Java,Hibernate,Database Design,Inheritance,我正在考虑Hibernate托管类层次结构的表布局,当然,在一般意义上,每个子类的表技术对我来说是最合适的。然而,通过逻辑思考,我对它的性能有一些担心,特别是当子类的数量增加时 为了给出一个非常简短(经典)的示例,假设您有以下几个类: public abstract class Animal { int pkey; String name; } public class Dog extends Animal { long numSlippersChewed; // int i

我正在考虑Hibernate托管类层次结构的表布局,当然,在一般意义上,每个子类的表技术对我来说是最合适的。然而,通过逻辑思考,我对它的性能有一些担心,特别是当子类的数量增加时

为了给出一个非常简短(经典)的示例,假设您有以下几个类:

public abstract class Animal {
   int pkey;
   String name;
}

public class Dog extends Animal {
   long numSlippersChewed; // int is not large enough...
}

public class Cat extends Animal {
   short miceCaught; // ... but here int is far bigger than required :-)
}
(我省略了getter、setter和Hibernate映射等,只是假设它们是基本的显而易见的情况)

这些实体的数据库表是有意义的,可以得到很好的非规范化,等等。然而,Hibernate做了什么查询来拉出一个单独的动物?我至少可以想到两种情况:

  • 具有一对一(或一对多)映射的一些其他实体,例如
    Human
    类的
    pet
    字段。这将存储pkey,因此当Hibernate获取人类对象时,它还需要获取相应的
    动物
    对象。当给定动物的pkey时,Hibernate将使用什么查询(/ies)来提取和解压实际的动物数据,因为它可能驻留在
    Cat
    Dog
    表中
  • HQL,例如来自动物的
    ,其中name='Rex'
    (假设名称是唯一的)。这与上面的类似,因为它允许您标识超类表中的一行,但您不知道要检查哪个子类表以获取更多详细信息。HQL是否允许您从抽象类发出查询?(不过,使用特定于子类的东西可以很好地工作,例如来自Cat的
    ,其中miceCaught>5
  • 我可以想出两种在SQL中实现这一点的方法,但这两种方法都不好看。一种是对给定pkey的每个子类表运行
    exists
    查询,然后从返回命中的表加载。或者,Hibernate可以在所有表中执行一些可怕的联合查询-基本上模拟每个层次结构方案的表,因为结果集将包括所有可能子类的属性,并且从子类表中选择的各个属性对于不相关的参数返回
    null
    。后一种情况甚至可能需要添加一个合成鉴别器列,以便Hibernate能够知道哪个子类表实际返回了行,从而知道它们应该被解析成什么Java类


    如果您有具体类型的子类型,情况也会变得更复杂:

    public class Greyhound extends Dog {
       float lifetimeRacingWinnings;
    }
    
    现在对于一个给定的动物pkey,在
    Dog
    灰狗
    表中可能有有效的行,这意味着我手动检查与pkey对应的类的第一种方法变得更加困难


    我如此担心的原因是,我希望在一个包含大约70个类的类层次结构上使用这种方法,最大嵌套链为4-5级,因此对所有这些类执行联合查询可能会有糟糕的性能。Hibernate是否有任何技巧来保持这种相对性能?或者pkey加载对其中一个类的引用需要很长时间吗?

    您会发现Hibernate使用一系列
    LEFT JOIN
    语句编写未知动物类型的查询,每个子类一个语句。因此,随着子类数量的增加,查询速度会变慢,并试图返回更广泛的结果集。因此,您是正确的,它不能很好地扩展大型类层次结构

    使用HQL,可以直接查询子类并访问其属性。然后,将使用单个
    内部联接来呈现

    我还没有尝试过多层次的继承。如果上面的内容还没有让您感到厌烦,建议您试试看——您可以打开SQL调试输出来查看发送到数据库的内容,或者简单地分析您的数据库。

    在我决定进行骨架测试之后

    我创建了一个抽象超类,
    ADTestA
    ,以及三级层次结构中的25个具体子类(我希望您可以猜出它们的名称)。每个类都有一个名称与其字母对应的整数字段,因此,例如,类
    ADTestG
    除了从直接父类
    ADTestB
    继承的
    b
    字段之外,还有一个int字段
    g
    ,以及顶级抽象超类中的
    pkey
    a
    字段

    从ADTestA发出HQL查询
    ,其中pkey=1
    生成以下SQL:

    select adtesta0_.pkey as pkey0_, adtesta0_.a as a0_, adtesta0_1_.b as b1_,
           adtesta0_2_.c as c2_, adtesta0_3_.d as d3_, adtesta0_4_.e as e4_,
           adtesta0_5_.f as f5_, adtesta0_6_.g as g6_, adtesta0_7_.h as h7_,
           adtesta0_8_.i as i8_, adtesta0_9_.j as j9_, adtesta0_10_.k as k10_,
           adtesta0_11_.l as l11_, adtesta0_12_.m as m12_, adtesta0_13_.n as n13_,
           adtesta0_14_.o as o14_, adtesta0_15_.p as p15_, adtesta0_16_.q as q16_,
           adtesta0_17_.r as r17_, adtesta0_18_.s as s18_, adtesta0_19_.t as t19_,
           adtesta0_20_.u as u20_, adtesta0_21_.v as v21_, adtesta0_22_.w as w22_,
           adtesta0_23_.x as x23_, adtesta0_24_.y as y24_, adtesta0_25_.z as z25_,
           case
               when adtesta0_6_.pkey is not null then 6
               when adtesta0_7_.pkey is not null then 7
               when adtesta0_8_.pkey is not null then 8
               when adtesta0_9_.pkey is not null then 9
               when adtesta0_10_.pkey is not null then 10
               when adtesta0_11_.pkey is not null then 11
               when adtesta0_12_.pkey is not null then 12
               when adtesta0_13_.pkey is not null then 13
               when adtesta0_14_.pkey is not null then 14
               when adtesta0_15_.pkey is not null then 15
               when adtesta0_16_.pkey is not null then 16
               when adtesta0_17_.pkey is not null then 17
               when adtesta0_18_.pkey is not null then 18
               when adtesta0_19_.pkey is not null then 19
               when adtesta0_20_.pkey is not null then 20
               when adtesta0_21_.pkey is not null then 21
               when adtesta0_22_.pkey is not null then 22
               when adtesta0_23_.pkey is not null then 23
               when adtesta0_24_.pkey is not null then 24
               when adtesta0_25_.pkey is not null then 25
               when adtesta0_1_.pkey is not null then 1
               when adtesta0_2_.pkey is not null then 2
               when adtesta0_3_.pkey is not null then 3
               when adtesta0_4_.pkey is not null then 4
               when adtesta0_5_.pkey is not null then 5
               when adtesta0_.pkey is not null then 0
           end as clazz_
    from ADTestA adtesta0_
               left outer join ADTestB adtesta0_1_ on adtesta0_.pkey=adtesta0_1_.pkey
               left outer join ADTestC adtesta0_2_ on adtesta0_.pkey=adtesta0_2_.pkey
               left outer join ADTestD adtesta0_3_ on adtesta0_.pkey=adtesta0_3_.pkey
               left outer join ADTestE adtesta0_4_ on adtesta0_.pkey=adtesta0_4_.pkey
               left outer join ADTestF adtesta0_5_ on adtesta0_.pkey=adtesta0_5_.pkey
               left outer join ADTestG adtesta0_6_ on adtesta0_.pkey=adtesta0_6_.pkey
               left outer join ADTestH adtesta0_7_ on adtesta0_.pkey=adtesta0_7_.pkey
               left outer join ADTestI adtesta0_8_ on adtesta0_.pkey=adtesta0_8_.pkey
               left outer join ADTestJ adtesta0_9_ on adtesta0_.pkey=adtesta0_9_.pkey
               left outer join ADTestK adtesta0_10_ on adtesta0_.pkey=adtesta0_10_.pkey
               left outer join ADTestL adtesta0_11_ on adtesta0_.pkey=adtesta0_11_.pkey
               left outer join ADTestM adtesta0_12_ on adtesta0_.pkey=adtesta0_12_.pkey
               left outer join ADTestN adtesta0_13_ on adtesta0_.pkey=adtesta0_13_.pkey
               left outer join ADTestO adtesta0_14_ on adtesta0_.pkey=adtesta0_14_.pkey
               left outer join ADTestP adtesta0_15_ on adtesta0_.pkey=adtesta0_15_.pkey
               left outer join ADTestQ adtesta0_16_ on adtesta0_.pkey=adtesta0_16_.pkey
               left outer join ADTestR adtesta0_17_ on adtesta0_.pkey=adtesta0_17_.pkey
               left outer join ADTestS adtesta0_18_ on adtesta0_.pkey=adtesta0_18_.pkey
               left outer join ADTestT adtesta0_19_ on adtesta0_.pkey=adtesta0_19_.pkey
               left outer join ADTestU adtesta0_20_ on adtesta0_.pkey=adtesta0_20_.pkey
               left outer join ADTestV adtesta0_21_ on adtesta0_.pkey=adtesta0_21_.pkey
               left outer join ADTestW adtesta0_22_ on adtesta0_.pkey=adtesta0_22_.pkey
               left outer join ADTestX adtesta0_23_ on adtesta0_.pkey=adtesta0_23_.pkey
               left outer join ADTestY adtesta0_24_ on adtesta0_.pkey=adtesta0_24_.pkey
               left outer join ADTestZ adtesta0_25_ on adtesta0_.pkey=adtesta0_25_.pkey
     where adtesta0_.pkey=1
    
    这不是很漂亮,并且与我希望可以避免的对每个层次表的有效模拟相对应

    因此,这类查询看起来将非常昂贵。我将考虑一下需要它们的频率(比如,与知道我想要一个
    ADTestP
    的实例并立即请求其中一个只加入所需父表的实例相比)。然而,我有一种感觉,这将不可避免地涉及到其他实体;换句话说,从类型为
    ADTestA
    的字段进行的一对一映射总是会涉及这种查找


    (另一方面,替代策略也不是闪亮的希望灯塔;按照层次结构路由查找表,并在一个表中包含数百列,听起来也不是很有效……)

    只要您仅通过Hibernate访问数据库,并且您没有重要数据,或者准备编写一个小的迁移脚本,您就应该能够在开发过程的后期就每个子类/层次结构的表做出决定。这就是ORM的优点,它抽象了数据库结构

    另一方面,我是“更喜欢组合而不是继承”(prefercomposition over inheritation)的忠实粉丝,我很怀疑一个拥有70个类的模型是否