【问题标题】:InheritanceType.JOINED strategy not working in with Spring BootInheritanceType.JOINED 策略不适用于 Spring Boot
【发布时间】:2017-04-09 20:54:14
【问题描述】:

我在使用 hibernate 实现 InheritanceType.JOINED 策略时遇到问题。

我总是遇到这种异常:

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:882) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362) ~[spring-orm-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1642) ~[spring-beans-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579) ~[spring-beans-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    ... 16 common frames omitted
Caused by: org.hibernate.MappingException: Could not instantiate persister org.hibernate.persister.entity.JoinedSubclassEntityPersister
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:112) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:77) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:348) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
    ... 22 common frames omitted
Caused by: org.hibernate.AssertionFailure: Table school_service.abstract_person not found
    at org.hibernate.persister.entity.AbstractEntityPersister.getTableId(AbstractEntityPersister.java:5118) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.persister.entity.JoinedSubclassEntityPersister.<init>(JoinedSubclassEntityPersister.java:433) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_51]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_51]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_51]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[na:1.8.0_51]
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:96) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    ... 26 common frames omitted

我创建了一个 Spring Boot / Gradle 项目来复制这里的错误:https://github.com/tamershahin/JoinTableTest

这是主类:

 @Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "person_type")
@Table(name = "abstract_person",schema = "school_service")
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @Id
    @GeneratedValue()
    @Column(name="person_id")
    private Long id;

    @Column(nullable = false, length = 125, name="name")
    @Getter
    @Setter
    String name;

   @Column(name = "person_type", nullable = false)
    @Getter@Setter
    String personType;

}

这是扩展它的一个:

@Entity
@DiscriminatorValue("student")
@Table(name = "student_detail",schema = "school_service")
@PrimaryKeyJoinColumn(name = "student_id", referencedColumnName = "person_id")
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class Student extends Person {

    @Column(length = 32, nullable = false)
    @Getter
    @Setter
    String email;

    @Column(length = 32, nullable = false)
    @Getter
    @Setter
    String className;
}

基本上我遵循 JPA 指南,事实上,如果我切换到 InheritanceType.TABLE_PER_CLASS 策略一切正常,但我不需要这种实现。

我调试了一下这个类:.../hibernate-core-5.0.11.Final-sources.jar!/org/hibernate/persister/entity/AbstractEntityPersister.java

我注意到这段代码:

for ( int j = 0; j < tables.length; j++ ) {
            if ( tableName.equalsIgnoreCase( tables[j] ) ) {
                return j;
            }
        }

永远不会返回正确的表,因为 tableName 始终包含架构而表不包含......这就是它无法找到表的原因。

是我错误配置/滥用某些东西还是这是一个正确的错误?

谢谢各位。

T

编辑:

我正在使用这个属性:

spring.jpa.hibernate.ddl-auto=create-drop

所以数据库应该由 Hibernate 根据他的需要生成,但在它之前一切都崩溃了。

我还尝试按照此处的说明手动创建该类: http://www.javaroots.com/2013/07/hibernate-inheritance-joined-strategy.html

但没有成功。

更新: 在@crafarlo 评论之后,我开始使用 application.properties,我发现删除了这个配置:

spring.jpa.properties.hibernate.default_schema

会成功的。

这是我的完整配置:

urlwithoutschema=jdbc:mysql://localhost:3306/
spring.datasource.url=${urlwithoutschema}${spring.datasource.schema}
spring.datasource.username=school
spring.datasource.password=school
spring.datasource.schema=school_service
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
#spring.jpa.properties.hibernate.default_schema=${spring.datasource.schema}

我不明白为什么这会影响映射类表,但它确实......有什么线索吗?

【问题讨论】:

  • “@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)”与加入有什么关系?!
  • 对不起,我的错:你是对的,我在这里复制粘贴的代码来自另一个使用 TABLE_PER_CLASS 的测试项目。但是github上共享的代码是正确的。我确认加入不起作用。
  • @Tamer 检查我的回复,您忘记了抽象类中的鉴别器列。单独做 Hibernate 并不是那么聪明:)
  • @cralfaro:我在使用和不使用明确声明的列的情况下进行测试,我在某处读到使用休眠自动生成不需要这样做。我正在更新 git 和 post 代码以反映在声明或不声明鉴别器列的情况下不工作的事实。不过很好:)
  • @Tamer 尝试此更改...在所有实体中添加架构,对所有表中的主键使用相同的列名,在本例中为“Person_id”只是为了简化案例跨度>

标签: java spring hibernate jpa spring-boot


【解决方案1】:

找不到表 school_service.abstract_person

缺少表 school_service.abstract_person。这对于 TABLE_PER_CLASS 不是必需的,但对于 JOINED,您需要为层次结构中的每个实体创建一个表。

【讨论】:

  • 我现在要求 hibernate 创建表,这有点奇怪.. 当创建它们时一切都失败了,这只发生在 InheritanceType.JOINED
【解决方案2】:

您不是通过 JOIN 进行继承。你应该使用这个:

@Entity
@Inheritance(strategy = InheritanceType.JOINED
@DiscriminatorColumn(name = "person_type")
@Table(name = "abstract_person",schema = "school_service")
@AllArgsConstructor
@NoArgsConstructor
public abstract class Person {
     @Id
     @Getter
     @Setter
     @Column(name = "ID")
     @GeneratedValue(...)
     private Integer id; 
     //...



@Entity
@DiscriminatorValue("student")
@Table(name = "student_detail",schema = "school_service")
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class Student extends Person {

    @Column(length = 32, nullable = false)
    @Getter
    @Setter
    String email;

    @Column(length = 32, nullable = false)
    @Getter
    @Setter
    String className;
}

并在您的子类表中定义与主表中相同的 PK。然后加入将起作用

更新:

你也忘了在抽象类中添加鉴别器列

@DiscriminatorColumn(name = "person_type", discriminatorType = DiscriminatorType.STRING)

...

@Getter @Setter
@Column(name = "person_type", nullable = false, insertable = false, updatable = false)
@Enumerated(value = EnumType.STRING)
private String type;

【讨论】:

  • 对不起,我的错:你是对的,我在这里复制粘贴的代码来自一个使用 TABLE_PER_CLASS 的测试项目。但是github上共享的代码是正确的。我确认加入不起作用。
  • 我尝试了您的代码,指定了列并设置了@Enumerated 注释。我还声明了一个 Enum 来保存 STUDENT 和 TEACHER 值。仍然不工作.. git 代码对你有用吗?
  • @Tamer 我没试过,不在内存中,我现在不想重新创建我的模式 :),我有完全相同的情况告诉我你的电子邮件,我会分享这个例子和你一起
  • 在您了解内存配置工作的线索后,我开始根据更新玩配置,现在它正在工作..谢谢!很高兴知道为什么:D p.s.:我确认在域类中您不需要声明的鉴别器列。
【解决方案3】:

从@Table 中删除 schema = "school_service",它应该可以解决您的问题。

来自

@Table(name = "abstract_person",schema = "school_service")

@Table(name = "abstract_person")

AbstractEntityPersister.class:3765

因为,在这段代码中,Hibernate 尝试将“school_service.abstract_person”与“abstract_person”进行比较。

public static int getTableId(String tableName, String[] tables) {
    for(int j = 0; j < tables.length; ++j) {
        if (tableName.equalsIgnoreCase(tables[j])) {
            return j;
        }
    }

    throw new AssertionFailure("Table " + tableName + " not found");
}

这就是您出现此错误的原因:

找不到表 school_service.abstract_person

【讨论】:

  • 这引导我朝着正确的方向前进!就我而言,我在 application.properties 中设置了spring.jpa.properties.hibernate.default_schema。确保也将其删除!否则,对于每个 @Table 注释,它都等效于 @Table(schema = "school_service")
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-13
  • 2018-10-18
  • 2012-04-17
  • 2020-07-10
  • 1970-01-01
  • 2019-08-19
  • 2018-07-04
相关资源
最近更新 更多