【发布时间】:2020-07-09 07:27:15
【问题描述】:
问题:我有一个遗留应用程序,其中包含一个抽象超类(比如说Task)和50 多个称为SubTask1 的子类等等。此外,这些子类具有多个具有相同名称的字段,例如filename、user 等。此外,这些子类与一个类具有不同的@ManyToOne 关系(比如说Property)。
现在,作为 ORM 工具,我们使用 hibernate,继承策略为 JOINED。现在,这些实体的查询性能非常糟糕。因此,为了提高性能,我尝试将继承策略更改为 SINGLE_TABLE 并让 hibernate 生成架构。
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
abstract public class Task {
public String type;
//Getters and setters
}
@Entity
public class SubTask1 extends Task {
public subTask1Field;
public String user;
public string filename;
@ManyToOne(optional = false)
public Property host;
//Getters and setters
}
@Entity
public class SubTask2 extends Task {
public subTask2Field;
public String user;
public string filename;
@ManyToOne(optional = false)
public Property host;
//Getters and setters
}
@Entity
public class Property {
@Unique
@Required
public String name;
@Required
public String value;
}
问题:在应用程序启动期间,我遇到异常。
2020-07-09 12:18:26,665 ERROR --- [ main] play : Can't start in PROD mode with errors
javax.persistence.PersistenceException: Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:925)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:900)
at play.db.jpa.JPAPlugin.onApplicationStart(JPAPlugin.java:204)
at play.plugins.PluginCollection.onApplicationStart(PluginCollection.java:616)
at play.Play.start(Play.java:538)
at play.Play.init(Play.java:309)
at play.server.Server.main(Server.java:160)
Caused by: org.hibernate.DuplicateMappingException: Table [Task] contains logical column name [fileName] referenced by multiple physical column names: [`filename`], [`fileName`]
at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.bindLogicalToPhysical(Configuration.java:3021)
at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.addBinding(Configuration.java:3008)
at org.hibernate.cfg.Configuration$MappingsImpl.addColumnBinding(Configuration.java:3053)
at org.hibernate.cfg.Ejb3Column.addColumnBinding(Ejb3Column.java:330)
at org.hibernate.cfg.Ejb3Column.linkWithValue(Ejb3Column.java:322)
at org.hibernate.cfg.annotations.SimpleValueBinder.linkWithValue(SimpleValueBinder.java:361)
at org.hibernate.cfg.annotations.SimpleValueBinder.make(SimpleValueBinder.java:336)
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyAndValue(PropertyBinder.java:193)
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:205)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2166)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:895)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:728)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3625)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3579)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1381)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1786)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:918)
... 6 common frames omitted
Exception in thread "main" play.exceptions.UnexpectedException: Unexpected Error
at play.Play.start(Play.java:568)
at play.Play.init(Play.java:309)
at play.server.Server.main(Server.java:160)
Caused by: javax.persistence.PersistenceException: Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:925)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:900)
at play.db.jpa.JPAPlugin.onApplicationStart(JPAPlugin.java:204)
at play.plugins.PluginCollection.onApplicationStart(PluginCollection.java:616)
at play.Play.start(Play.java:538)
... 2 more
Caused by: org.hibernate.DuplicateMappingException: Table [Task] contains logical column name [fileName] referenced by multiple physical column names: [`filename`], [`fileName`]
at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.bindLogicalToPhysical(Configuration.java:3021)
at org.hibernate.cfg.Configuration$MappingsImpl$TableColumnNameBinding.addBinding(Configuration.java:3008)
at org.hibernate.cfg.Configuration$MappingsImpl.addColumnBinding(Configuration.java:3053)
at org.hibernate.cfg.Ejb3Column.addColumnBinding(Ejb3Column.java:330)
at org.hibernate.cfg.Ejb3Column.linkWithValue(Ejb3Column.java:322)
at org.hibernate.cfg.annotations.SimpleValueBinder.linkWithValue(SimpleValueBinder.java:361)
at org.hibernate.cfg.annotations.SimpleValueBinder.make(SimpleValueBinder.java:336)
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyAndValue(PropertyBinder.java:193)
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:205)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2166)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:895)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:728)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3625)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3579)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1381)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1786)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:918)
... 6 more
问题:
- 是否甚至可以在不更改我的实体类的情况下转换这样的继承策略?如果是,您会建议对此进行哪些更改?
- 这里有没有其他方法可以提高查询性能?每当我尝试获取
Task实体时,它都会在所有SubTask表上创建一个连接,每个SubTask表都与Property表连接。
【问题讨论】:
-
您正在使用继承,为什么还要复制字段?即使加入也没有意义。 JOINED 和 SINGLE_TABLE 的性能没有变化。您必须有另一个性能问题。你检查生成的 SQL 了吗?
-
是的,我同意重复字段的问题。它不是设计它的理想方式。但由于它是一个遗留应用程序,我对此无能为力。此外,这些类很大,我什至不能冒险巩固超类中的共同领域。是的,我已经看到了生成的 SQL。它们是 600 多行 sql 生成的,包含所有表之间的连接。我的感觉是,如果我更改继承类型,所有这些连接都将不存在。
-
是的,但所有数据都将位于同一个数据库表中。而且您说您无法更改旧版应用程序。使用 SINGLE_TABLE 您将不得不更改数据库模型
-
是的,我愿意更改数据库。不会有别的办法了。我希望对 Java 代码进行最小的更改。到目前为止,我只更改了一行,即更改超类的继承类型。
-
所以答案是:只要你的类中有重复的属性,就没有办法让它工作