我正在尝试优化我的数据库表。但我现在对Hibernate / JPA缺乏了解并不是很有帮助。
我有一个看起来或多或少的Java对象模型:
ParentClass
SubClass1
SubSubClass1
SubSubClass2
SubSubClass3
SubSubClass4
SubClass2
SubSubClass5
SubSubClass6
所有类都包含Fields。大约50%的所有字段都在ParentClass中。 40-50%属于SubClass1级别,0-10%属于SubSubclass级别。许多SubSubClass *类都是空的,但是需要识别Type。
尝试1:
因此。我们首先做的是在Parentclass上使用TABLE_PER_CLASS策略。这导致了大量的表格:
SubSubClass1
SubSubClass2
SubSubClass3
SubSubClass4
SubSubClass5
SubSubClass6
这不是很酷,因为这些表中所有列的50%在所有表之间共享,而其他Rest在3-4个表之间共享。
尝试2:
我们将策略更改为SINGLE_TABLE。
结果表只是一个很大的“ParentClass”表。但由于所有列中只有约50%在所有子类之间共享,因此许多字段必须设置为Null,这不是那么性感。
尝试3:
接下来的尝试是将TABLE_PER_CLASS策略与“SINGLE_TABLE”策略混合。我决定不使用JOIN TABLES作为策略,因为我必须使用许多小的子类,这会导致创建许多包含一个或两个Columns的小表。
所以,我正在回答这个问题的答案:How to mix inheritance strategies with JPA annotations and Hibernate?
我现在想要将ParentClass中的所有值放在一个表中,将第一个SubLevel中的所有值放入一个表中。这应该导致这样的Schema:
ParentClass
- SubClass1
- SubClass2
- SubClass3
这是我的代码:
@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class ParentClass {
private String value1;
}
@MappedSuperclass
@SecondaryTable(name = "SubClass1")
public abstract class SubClass1 extends ParentClass {
@Column(table = "SubClass1")
private String value11;
}
@MappedSuperclass
@SecondaryTable(name = "SubClass2")
public abstract class SubClass2 extends ParentClass {
@Column(table = "SubClass2")
private String value12;
}
@Entity
@SecondaryTable(name = "SubClass1")
public abstract class SubSubClass1 extends SubClass1 {
@Column(table = "SubClass1")
private String value111;
}
@Entity
@SecondaryTable(name = "SubClass2")
public abstract class SubSubClass2 extends SubClass2 {
@Column(table = "SubClass2")
private String value121;
}
实际上效果很好。但是我的问题已经开始了:
首先,我在SchemaUpdate期间收到以下错误。
Unsuccessful: alter table schema.SubClass1 add constraint AAAAAAA36D68C4 foreign key (id) references schema.ParentClass
ORA-02275: such a referential constraint already exists in the table
Unsuccessful: alter table schema.SubClass2 add constraint AAAAAAA36D68C4 foreign key (id) references schema.ParentClass
ORA-02275: such a referential constraint already exists in the table
我认为这些错误是由于我在多个级别上不止一次使用SecondaryTables造成的。每次我使用它们时,都会创建另一个约束。这当然不起作用,因为约束已经存在。
第二个问题是如果它应该从所有这些表中获取数据,那么Hibernate会变得疯狂:
select
*
from
( select
parentclass0_.value1 as value1_1_,
parentclass0_1_.value11 as erste1_3_,
parentclass0_1_.value111 as value1113_3_,
parentclass0_2_.value12 as value122_3_,
parentclass0_2_.value121 as value1214_3_,
parentclass0_.DTYPE as DTYPE2_
from
schema.parentclass parentclass0_
left outer join
schema.subclass1 parentclass0_1_
on parentclass0_.id=parentclass0_1_.id
left outer join
schema.subclass1 parentclass0_2_
on parentclass0_.id=parentclass0_2_.id
left outer join
schema.subclass1 parentclass0_3_
on parentclass0_.id=parentclass0_3_.id
left outer join
schema.subclass2 parentclass0_4_
on parentclass0_.id=parentclass0_4_.parentclass_id
left outer join
schema.subclass1 parentclass0_5_
on parentclass0_.id=parentclass0_5_.id
left outer join
schema.subclass1 parentclass0_6_
on parentclass0_.id=parentclass0_6_.id )
每次在子类中使用@SecondaryTable注释时,它都会加入同一个表。它一次又一次地加入它。我看了一下Oracle的解释计划,它告诉我这个计划会自动优化,如果我要优化它,我会使用它。但无论如何。很奇怪。
问题:
如何防止Hibernate多次创建相同的约束?我认为这也可以解决连接问题。或者应该停止尝试这样做,还有另一种方式吗?
答案 0 :(得分:9)
从纯粹的JPA角度来看,你不能在继承树中混合策略。引用JPA规范(11.1.20)
继承注释定义了要使用的继承策略 对于实体类层次结构。它在实体类中指定 这是实体类层次结构的根。 本规范不要求支持继承策略的组合。 便携式应用程序应该只在实体层次结构中使用单个继承策略。
JDO是唯一允许您在树下定义不同策略的持久性规范。
答案 1 :(得分:2)
我认为你应该真正使用SINGLE_TABLE策略。 50%的共享列真的不是那么糟糕,特别是如果你知道这个数字不会随着时间的推移而减少(我的意思是你认为有一天那个表中会有500列,只有40列共享?),如果您要对根实体运行大量查询,那么它将始终与其他策略进行多次连接。
在工作中我们刚刚讨论过这个问题。 选择SINGLE_TABLE策略是因为我们认为列数不会爆炸,我们可能只有5%的共享属性结束:(。所以我认为它适用于您的情况,但请注意并考虑您的数据如何运行被访问。
编辑:因为不可能混合策略而你不需要很多表: 如果您有140个子实体和50%的共享属性,那么您真的应该使用SINGLE_TABLE策略!!!!!!
答案 2 :(得分:0)
为什么不在父类上使用策略JOINED?你仍然会有很多表但没有多余的属性。