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

Quarkus原生镜像中HibernatePersistenceProvider替代方案咨询

Quarkus原生模式下替代HibernatePersistenceProvider的解决方案

Quarkus为优化原生镜像体积,通过Substitute机制将org.hibernate.jpa.HibernatePersistenceProvider完全排除,导致手动实例化该类时触发DeletedElementException。FastBootHibernatePersistenceProvider作为替代实现,虽然构造参数看似复杂,但无需完全重写现有逻辑,以下是几种可行方案:

方案1:利用Quarkus多持久化单元(PU)配置(推荐)

Quarkus原生支持多数据源和多PU配置,直接通过配置文件定义H2缓存的PU,由框架自动管理EntityManagerFactory,完全避开手动实例化Provider的问题。

配置步骤:

  1. 在application.properties中添加H2缓存数据源和对应的Hibernate ORM配置:
# 主PostgreSQL数据源配置
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=your-postgres-user
quarkus.datasource.password=your-postgres-pass
quarkus.datasource.jdbc.url=jdbc:postgresql://your-postgres-host:5432/db-name
quarkus.hibernate-orm.persistence-unit-name=main
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQLDialect

# H2缓存数据源配置
quarkus.datasource.cache.db-kind=h2
quarkus.datasource.cache.username=sa
quarkus.datasource.cache.password=
quarkus.datasource.cache.jdbc.url=jdbc:h2:mem:cache-db;DB_CLOSE_DELAY=-1
quarkus.hibernate-orm.cache.persistence-unit-name=cache
quarkus.hibernate-orm.cache.dialect=org.hibernate.dialect.H2Dialect
# 指定缓存PU需要映射的实体类
quarkus.hibernate-orm.cache.entities=com.yourpackage.CacheEntity
  1. 注入H2缓存对应的EntityManagerFactory:
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceUnit;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class CacheService {
    @Inject
    @PersistenceUnit("cache")
    EntityManagerFactory cacheEntityManagerFactory;

    // 使用cacheEntityManagerFactory操作H2缓存
}

这种方式完全符合Quarkus原生模式的设计,框架会自动处理原生镜像的优化和依赖注入,无需手动处理Provider。

方案2:手动使用FastBootHibernatePersistenceProvider

如果必须手动控制EntityManagerFactory的创建,可以通过构建QuarkusPersistenceUnitDefinition来适配FastBootHibernatePersistenceProvider的构造要求:

import io.quarkus.hibernate.orm.runtime.boot.QuarkusPersistenceUnitDefinition;
import io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider;
import jakarta.persistence.EntityManagerFactory;
import java.util.Collections;
import java.util.List;

public class CacheEMFBuilder {
    public EntityManagerFactory createCacheEntityManagerFactory() {
        // 构建H2缓存的PU定义
        QuarkusPersistenceUnitDefinition unitDefinition = QuarkusPersistenceUnitDefinition.builder()
                .setPersistenceUnitName("cache")
                .setDialect(org.hibernate.dialect.H2Dialect.class)
                .setManagedClasses(List.of(CacheEntity.class))
                // 配置H2数据源,也可以复用Quarkus已配置的数据源
                .setJdbcUrl("jdbc:h2:mem:cache-db;DB_CLOSE_DELAY=-1")
                .setJdbcUser("sa")
                .setJdbcPassword("")
                .build();

        FastBootHibernatePersistenceProvider provider = new FastBootHibernatePersistenceProvider();
        return provider.createContainerEntityManagerFactory(unitDefinition, Collections.emptyMap());
    }
}

注意:如果使用Quarkus管理的数据源,可通过io.quarkus.datasource.runtime.DataSourceProvider获取已配置的H2数据源,替换手动设置的JDBC参数。

方案3:直接使用Hibernate原生Bootstrap API

绕过PersistenceProvider层,直接用Hibernate的SessionFactory Bootstrap API构建EntityManagerFactory,这种方式需要手动配置原生镜像的反射规则:

代码示例:

import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import jakarta.persistence.EntityManagerFactory;

public class CacheEMFBuilder {
    public EntityManagerFactory createCacheEntityManagerFactory() {
        BootstrapServiceRegistry bootstrapRegistry = new BootstrapServiceRegistryBuilder()
                .build();

        MetadataSources metadataSources = new MetadataSources(bootstrapRegistry)
                .addAnnotatedClass(CacheEntity.class);

        Metadata metadata = metadataSources.getMetadataBuilder()
                .applySetting(AvailableSettings.DIALECT, org.hibernate.dialect.H2Dialect.class.getName())
                .applySetting(AvailableSettings.JDBC_URL, "jdbc:h2:mem:cache-db")
                .applySetting(AvailableSettings.JDBC_USER, "sa")
                .applySetting(AvailableSettings.JDBC_PASSWORD, "")
                .build();

        SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder();
        return sessionFactoryBuilder.build().unwrap(EntityManagerFactory.class);
    }
}

原生镜像反射配置:

在src/main/resources/META-INF/native-image/your-group-id/your-artifact-id/reflect-config.json中添加以下内容(按需调整):

[
    {
        "name": "com.yourpackage.CacheEntity",
        "allDeclaredConstructors": true,
        "allDeclaredFields": true,
        "allDeclaredMethods": true
    },
    {
        "name": "org.hibernate.dialect.H2Dialect",
        "allDeclaredConstructors": true
    }
]

总结

优先选择方案1,完全贴合Quarkus的原生模式设计,无需额外处理原生镜像的兼容性问题;如果必须手动控制EMF创建,方案2是更符合Quarkus优化逻辑的选择;方案3作为兜底,适合需要完全自定义Hibernate初始化流程的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 19:13:17