Java EE下Hibernate配置多H2持久化单元测试仅首个通过报Not an entity错误
问题根因
这个问题和H2是否支持多个内存数据库无关,你目前的用法本身是合法的——H2原生支持同JVM内创建多个命名不同的内存数据库,彼此完全隔离。你遇到的报错本质是批量测试时持久化上下文未隔离,具体原因有两个:
- 你第二个持久化单元
CompanyPersistenceServiceBeanIntTest的配置中,仅注册了com.data.company.Company这一个实体类,且开了<exclude-unlisted-classes>true</exclude-unlisted-classes>,这个PU的元数据模型中本来就没有ItemHistory类的信息 - 批量运行测试时,前一个测试初始化的
EntityManagerFactory/持久化上下文没有被销毁,或者第二个测试错误加载了不匹配的持久化单元,导致业务代码用到ItemHistory时,从当前加载的PU元数据中找不到对应实体定义,才抛出Not an entity错误
解决方案
按以下步骤排查修改即可解决:
确认每个测试类绑定了正确的持久化单元
初始化EntityManagerFactory时必须显式指定对应PU的名称,不能依赖默认加载逻辑:- 对应
ItemHistory相关测试:EntityManagerFactory emf = Persistence.createEntityManagerFactory("ItemHistoryPersistenceServiceBeanIntTest"); - 对应
Company相关测试:EntityManagerFactory emf = Persistence.createEntityManagerFactory("CompanyPersistenceServiceBeanIntTest");
如果使用Spring/SpringBoot做测试,给每个测试类加上@DirtiesContext注解,强制测试跑完后销毁Spring上下文,避免上下文缓存复用前一个测试的持久化单元。
- 对应
修复老版本Hibernate元数据共享问题
你用的org.hibernate.ejb.HibernatePersistence是Hibernate 4.x及更早版本的提供器,该版本存在实体元数据全局缓存的bug,同一个类加载器下多个PU加载时会复用已扫描的实体元数据。给两个persistence-unit标签下都添加以下配置即可:
<shared-cache-mode>NONE</shared-cache-mode>
同时在properties中添加禁用元数据缓存的配置:
<property name="hibernate.ejb.metamodel.population" value="enabled"/>
- 修正hbm2ddl配置
你已经通过JDBC URL的INIT参数指定了建表和插数的SQL脚本,完全不需要把hibernate.hbm2ddl.auto设为update,改为none即可完全复用你自定义的SQL脚本,稳定性更高。之前换其他值无法插数是因为create/create-drop配置会先清空表结构,覆盖你INIT脚本执行的结果。
补充说明
如果要实现测试跑完后自动销毁H2内存库,不需要依赖DB_CLOSE_DELAY参数,只需要在每个测试类的@After/@AfterEach方法中显式调用emf.close()关闭当前持久化单元的工厂即可,最后一个连接断开后H2会自动销毁对应内存库。
内容的提问来源于stack exchange,提问作者WesternGun
相关产品推荐
相关产品推荐

