Quarkus集成quarkus-hibernate-reactive时,设置quarkus.hibernate-orm.database.generation=update导致启动失败
update模式启动报错问题 我太懂这个坑了!你遇到的问题是Quarkus Hibernate Reactive在处理schema更新时的典型限制:当把quarkus.hibernate-orm.database.generation设为update时启动失败,但drop-and-create能正常跑,从堆栈里的java.sql.SQLException: Not using JDBC就能直接定位原因。
问题本质
Hibernate Reactive执行update操作时,需要读取数据库现有的schema元数据来对比更新,但这个元数据读取操作必须依赖JDBC连接;而drop-and-create是直接清空重建,不需要读取现有结构,所以完全能通过Reactive驱动完成。但你当前只配置了Reactive数据源,没有提供JDBC连接池,导致Hibernate拿不到所需的JDBC连接来执行update流程。
两种解决方案
方案1:补充JDBC数据源配置(快速解决开发场景)
在你的application.properties里添加JDBC相关配置,让Hibernate能获取JDBC连接:
quarkus.http.port=8085 quarkus.datasource.db-kind=postgresql quarkus.datasource.username=admin quarkus.datasource.password=admin # 保留原有Reactive数据源配置 quarkus.datasource.reactive.url=postgresql://localhost:5000/keycloak_sample # 新增JDBC数据源配置 quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5000/keycloak_sample myapp.schema.create=true quarkus.hibernate-orm.database.generation=update quarkus.hibernate-orm.log.sql=true
同时要确保项目引入了JDBC驱动依赖(Maven示例):
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-jdbc-postgresql</artifactId> </dependency>
方案2:用专业迁移工具(推荐生产环境)
hibernate-orm.database.generation=update本身就不适合生产环境,风险很高。更推荐用Flyway或Liquibase这类schema迁移工具,它们对Reactive数据源支持很好,能安全管理schema变更:
比如添加Flyway依赖后,编写SQL迁移脚本,Quarkus会自动在启动时执行:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-flyway</artifactId> </dependency>
然后把quarkus.hibernate-orm.database.generation设为none,让Flyway接管schema管理。
你的原始配置与错误堆栈
application.properties
quarkus.http.port=8085 quarkus.datasource.db-kind=postgresql quarkus.datasource.username=admin quarkus.datasource.password=admin quarkus.datasource.reactive.url=postgresql://localhost:5000/keycloak_sample myapp.schema.create=true quarkus.hibernate-orm.database.generation=drop-and-create quarkus.hibernate-orm.log.sql=true
错误堆栈
java.lang.RuntimeException: java.lang.RuntimeException: Failed to start quarkus at io.quarkus.dev.appstate.ApplicationStateNotification.waitForApplicationStart(ApplicationStateNotification.java:51) at io.quarkus.runner.bootstrap.StartupActionImpl.runMainClass(StartupActionImpl.java:145) at io.quarkus.deployment.dev.IsolatedDevModeMain.restartApp(IsolatedDevModeMain.java:191) at io.quarkus.deployment.dev.IsolatedDevModeMain.restartCallback(IsolatedDevModeMain.java:175) at io.quarkus.deployment.dev.RuntimeUpdatesProcessor.doScan(RuntimeUpdatesProcessor.java:254) at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$2.handle(VertxHttpHotReplacementSetup.java:64) at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$2.handle(VertxHttpHotReplacementSetup.java:54) at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$2(ContextImpl.java:313) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:829) Caused by: java.lang.RuntimeException: Failed to start quarkus at io.quarkus.runner.ApplicationImpl.doStart(ApplicationImpl.zig:918) at io.quarkus.runtime.Application.start(Application.java:90) at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:100) at io.quarkus.runtime.Quarkus.run(Quarkus.java:66) at io.quarkus.runtime.Quarkus.run(Quarkus.java:42) at io.quarkus.runtime.Quarkus.run(Quarkus.java:119) at io.quarkus.runner.GeneratedMain.main(GeneratedMain.zig:29) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at io.quarkus.runner.bootstrap.StartupActionImpl$3.run(StartupActionImpl.java:134) ... 1 more Caused by: org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99) at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:69) at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:60) at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:40) at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.initializeSequences(DatabaseInformationImpl.java:65) at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.<init>(DatabaseInformationImpl.java:59) at org.hibernate.tool.schema.internal.Helper.buildDatabaseInformation(Helper.java:155) at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:96) at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:184) at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73) at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:318) at org.hibernate.reactive.session.impl.ReactiveSessionFactoryImpl.<init>(ReactiveSessionFactoryImpl.java:33) at io.quarkus.hibernate.reactive.runtime.boot.FastBootReactiveEntityManagerFactoryBuilder.build(FastBootReactiveEntityManagerFactoryBuilder.java:34) at io.quarkus.hibernate.reactive.runtime.FastBootHibernateReactivePersistenceProvider.createEntityManagerFactory(FastBootHibernateReactivePersistenceProvider.java:83) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:80) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55) at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:118) at io.quarkus.hibernate.orm.runtime.JPAConfig.startAll(JPAConfig.java:42) at io.quarkus.hibernate.orm.runtime.JPAConfig_Subclass.startAll$$superaccessor5(JPAConfig_Subclass.zig:763) at io.quarkus.hibernate.orm.runtime.JPAConfig_Subclass$$function$$5.apply(JPAConfig_Subclass$$function$$5.zig:29) at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54) at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63) at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51) at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521) at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41) at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41) at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32) at io.quarkus.hibernate.orm.runtime.JPAConfig_Subclass.startAll(JPAConfig_Subclass.zig:721) at io.quarkus.hibernate.orm.runtime.HibernateOrmRecorder.startAllPersistenceUnits(HibernateOrmRecorder.java:88) at io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits951856026.deploy_0(HibernateOrmProcessor$startPersistenceUnits951856026.zig:74) at io.quarkus.deployment.steps.HibernateOrmProcessor$startPersistenceUnits951856026.deploy(HibernateOrmProcessor$startPersistenceUnits951856026.zig:40) at io.quarkus.runner.ApplicationImpl.doStart(ApplicationImpl.zig:764) ... 12 more Caused by: java.sql.SQLException: Not using JDBC at org.hibernate.reactive.provider.service.NoJdbcConnectionProvider.getConnection(NoJdbcConnectionProvider.java:25) at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:180) at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:43) ... 42 more
内容的提问来源于stack exchange,提问作者jithset

