You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hibernate ORM时出现Unknown entity错误,求解决

Hibernate Unknown Entity 错误排查与解决

项目环境

  • 开发工具:Apache NetBeans 17
  • 构建工具:Gradle 8.0
  • 目标Java版本:Java 8
  • 技术栈版本:
    • Hibernate: org.hibernate.orm:hibernate-java8:6.0.0.Alpha7
    • H2数据库: com.h2database:h2:2.2.224
    • Jakarta Persistence API: jakarta.persistence:jakarta.persistence-api:3.0.0
    • ShadowJar插件: com.github.johnrengelman:shadow:8.1.1

问题描述

运行测试程序时,始终抛出Unknown entity错误,无法识别Student实体类。

代码与配置参考

Main.java

import java.util.List;
import org.mypackage.database.*;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class Main {
    public static void main(String[] args) {

        Student student = new Student("John", "Cena", "johncena@blablabla.com");
        
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            System.out.println("INFO: Session opened");
            transaction = session.beginTransaction();
            session.save(student);
            transaction.commit();
        } catch (Exception e) {
            System.out.println("ERROR" + e.getMessage());
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }

        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            List < Student > students = session.createQuery("from Student", Student.class).list();
            students.forEach(s -> System.out.println(s.getFirstName()));
        } catch (Exception e) {
            System.out.println("ERROR" + e.getMessage());
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }
}

Student.java

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "student")
public class Student{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "email")
    private String email;

    public Student() {

    }

    public Student(String firstName, String lastName, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]";
    }
}

HibernateUtil.java

package org.mypackage.database;

import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

public class HibernateUtil {
    private static StandardServiceRegistry registry;
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().build();
        try {
                    sessionFactory = new MetadataSources(registry)
                            .addAnnotatedClass(Student.class)
                            .buildMetadata()
                            .buildSessionFactory();
        }
        catch (Exception e) {
            StandardServiceRegistryBuilder.destroy(registry);
        }
                
            } catch (Exception e) {
                e.printStackTrace();
                if (registry != null) {
                    StandardServiceRegistryBuilder.destroy(registry);
                }
            }
        }
        
        return sessionFactory;
    }

    public static void shutdown() {
        if (registry != null) {
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
}

hibernate.properties

# Database connection settings
hibernate.connection.driver_class=org.h2.Driver
hibernate.connection.url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1
hibernate.connection.username=sa
hibernate.connection.password=
hibernate.connection.pool_size=1

hibernate.dialect=org.hibernate.dialect.H2Dialect

# Echo all executed SQL to console
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.highlight_sql=true

hibernate.hbm2ddl.auto=create-drop

# Automatically export the schema
hibernate.current_session_context_class=thread
hibernate.hbm2ddl.auto=create
hibernate.dbcp.initialSize=5
hibernate.dbcp.maxTotal=20
hibernate.dbcp.maxIdle=10
hibernate.dbcp.minIdle=5
hibernate.dbcp.maxWaitMillis=-1

build.gradle

buildscript {
    repositories {
        gradlePluginPortal()
    }
    dependencies {
        classpath 'com.github.johnrengelman:shadow:8.1.1'
    }
}

plugins {
    id 'com.github.johnrengelman.shadow' version '8.1.1'
    id 'java'
    id 'application'
}

apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'java'

mainClassName = 'org.mypackage.Main'
group = 'org.mypackage'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.hibernate.orm:hibernate-java8:6.0.0.Alpha7'
    implementation 'com.h2database:h2:2.2.224'
    implementation 'jakarta.persistence:jakarta.persistence-api:3.0.0'

    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'
}

test {
    useJUnitPlatform()
}

compileJava   {
  sourceCompatibility = '1.8'
  targetCompatibility = '1.8'
}

问题原因分析

  1. 实体类包路径缺失:Student类未声明包路径,默认处于无包名的默认包中。而Main.java导入的是org.mypackage.database.*,HibernateUtil也尝试加载该包下的Student类,导致类路径不匹配,Hibernate无法识别实体。
  2. Hibernate依赖选择错误:Hibernate 6.x版本中,hibernate-java8 artifact已被整合到核心包hibernate-core中,继续使用hibernate-java8可能导致缺少实体扫描的必要组件。
  3. HibernateUtil变量覆盖问题:内部代码中声明的final StandardServiceRegistry registry覆盖了类成员变量,导致shutdown方法无法正确清理资源(虽不是实体错误的直接原因,但属于代码缺陷)。
  4. 配置重复冲突:hibernate.properties中重复设置了hibernate.hbm2ddl.auto,可能导致配置生效异常。

解决方案

1. 给Student类添加正确的包声明

在Student.java的最开头添加包路径:

package org.mypackage.database;

2. 修复HibernateUtil的变量覆盖问题

修改HibernateUtil.java,将内部创建的registry赋值给类成员变量:

package org.mypackage.database;

import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

public class HibernateUtil {
    private static StandardServiceRegistry registry;
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                // 移除final,赋值给类成员registry
                registry = new StandardServiceRegistryBuilder().build();
                try {
                    sessionFactory = new MetadataSources(registry)
                            .addAnnotatedClass(Student.class)
                            .buildMetadata()
                            .buildSessionFactory();
                } catch (Exception e) {
                    StandardServiceRegistryBuilder.destroy(registry);
                    throw e; // 重新抛出异常,确保外层能捕获处理
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (registry != null) {
                    StandardServiceRegistryBuilder.destroy(registry);
                }
            }
        }
        return sessionFactory;
    }

    public static void shutdown() {
        if (registry != null) {
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
}

3. 替换Hibernate依赖为核心包

修改build.gradle中的依赖配置,将hibernate-java8替换为hibernate-core:

dependencies {
    implementation 'org.hibernate.orm:hibernate-core:6.0.0.Alpha7'
    implementation 'com.h2database:h2:2.2.224'
    implementation 'jakarta.persistence:jakarta.persistence-api:3.0.0'

    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'
}

4. 清理重复的配置项

在hibernate.properties中移除重复的hibernate.hbm2ddl.auto设置,保留一个即可:

# 移除其中一行,推荐保留create-drop用于测试场景
hibernate.hbm2ddl.auto=create-drop

验证步骤

  1. 执行Gradle的clean和build任务,重新编译项目
  2. 运行Main类,检查是否成功保存和查询Student实体,不再抛出Unknown entity错误

内容的提问来源于stack exchange,提问作者z3hir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:35:53