Hibernate ORM tries to connect to the database on startup even with schema validation disabled
Apparently it tries to connect to the database to retrieve metadata. This might be a bug: I think we disable that metadata collection on startup, because that cannot work with native images, so I don't know why that collection happens anyway...
See #29846, quoting:
I think is connecting to database. With not option to delay the connection.
no validate the scheme = false.
Originally posted by @sirlordt in https://github.com/quarkusio/quarkus/issues/29846#issuecomment-1350022222
/cc @Sanne(hibernate-orm), @gsmet(hibernate-orm)
@sirlordt you're using the configuration property javax.persistence.validation.mode, which is not expected to work in application.properties. You should use the Quarkus-specific property quarkus.hibernate-orm.database.generation.
That being said, even taking that mistake into account, the stacktraces still look suspicious. We need to have a closer look.
See also #34309. It seems Hibernate ORM does try to connect to the DB on startup to retrieve metadata, here's the stack trace:
handlerFromSharedCache:288, ConnectionPool (io.agroal.pool)
getConnection:249, ConnectionPool (io.agroal.pool)
getConnection:86, DataSource (io.agroal.pool)
getConnection:23, QuarkusConnectionProvider (io.quarkus.hibernate.orm.runtime.customized)
obtainConnection:316, JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess (org.hibernate.engine.jdbc.env.internal)
initiateService:152, JdbcEnvironmentInitiator (org.hibernate.engine.jdbc.env.internal)
initiateService:34, JdbcEnvironmentInitiator (org.hibernate.engine.jdbc.env.internal)
initiateService:119, StandardServiceRegistryImpl (org.hibernate.boot.registry.internal)
createService:264, AbstractServiceRegistryImpl (org.hibernate.service.internal)
initializeService:239, AbstractServiceRegistryImpl (org.hibernate.service.internal)
getService:216, AbstractServiceRegistryImpl (org.hibernate.service.internal)
configure:45, JdbcServicesImpl (org.hibernate.engine.jdbc.internal)
configureService:125, StandardServiceRegistryImpl (org.hibernate.boot.registry.internal)
initializeService:248, AbstractServiceRegistryImpl (org.hibernate.service.internal)
getService:216, AbstractServiceRegistryImpl (org.hibernate.service.internal)
<init>:274, SessionFactoryOptionsBuilder (org.hibernate.boot.internal)
buildSessionFactoryOptionsBuilder:70, PrevalidatedQuarkusMetadata (io.quarkus.hibernate.orm.runtime.recording)
build:81, FastBootEntityManagerFactoryBuilder (io.quarkus.hibernate.orm.runtime.boot)
createEntityManagerFactory:74, FastBootHibernatePersistenceProvider (io.quarkus.hibernate.orm.runtime)
createEntityManagerFactory:80, Persistence (jakarta.persistence)
createEntityManagerFactory:55, Persistence (jakarta.persistence)
get:156, JPAConfig$LazyPersistenceUnit (io.quarkus.hibernate.orm.runtime)
run:64, JPAConfig$1 (io.quarkus.hibernate.orm.runtime)
run:833, Thread (java.lang)
And it seems to be on purpose; we disable this metadata retrieval during static init but re-enable it during runtime init (application startup):
https://github.com/quarkusio/quarkus/blob/143a61b6cee6f331c96c17c251f6f6e75634cb15/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/FastBootHibernatePersistenceProvider.java#L230-L231
I believe the only way to prevent this metadata retrieval would be #13522, which involves a fair amount of work, in particular upstream, and may require explicit configuration from users since some metadata just cannot be inferred without connecting to the DB (e.g. sometimes Hibernate ORM needs to know about some DB settings).
FWIW we'll need to address at least #13522 and this upstream issue before we can work on this, and maybe more: https://hibernate.atlassian.net/browse/HHH-17425
Hey we're having the same problem that Quarkus tries to connect to the database during boot (which does not exist at that time).
This can usually be solved easily (like in Spring Boot) by providing the following properties:
hibernate.boot.allow_jdbc_metadata_access=falsejakarta.persistence.database-product-name=...jakarta.persistence.database-major-version=...jakarta.persistence.database-minor-version=...
I supplied these using quarkus.hibernate-orm.unsupported-properties."full-property-key" however some are ignored:
Persistence-unit [<default>] sets property 'hibernate.boot.allow_jdbc_metadata_access' to a custom value through 'quarkus.hibernate-orm.unsupported-properties."hibernate.boot.allow_jdbc_metadata_access"', but Quarkus already set that property independently. The custom value will be ignored.
Persistence-unit [<default>] sets property 'jakarta.persistence.database-product-name' to a custom value through 'quarkus.hibernate-orm.unsupported-properties."jakarta.persistence.database-product-name"', but Quarkus already set that property independently. The custom value will be ignored.
Is it somehow possible to enforce setting these values during runtime? Or is there some other way to do that?
Fun Fact:
Manually overwriting FastBootHibernatePersistenceProvider and removing this continue makes it work.
Hey,
It's not currently possible.
hibernate.boot.allow_jdbc_metadata_access=false
This is the property that needs to be exposed in Quarkus. A PR to simply add a flag for this configuration in Quarkus (e.g. quarkus.hibernate-orm.start-offline) could fix your whole use case. The change itself is most likely trivial, though automated testing will be a bit less so, and we'll certainly need #13522 as a follow-up -- but @sebersole has already started working on that one.
jakarta.persistence.database-product-name=...
jakarta.persistence.database-major-version=...
jakarta.persistence.database-minor-version=...
These don't make sense to set in Quarkus, because Quarkus already sets the first one, and the second/third one can be set through quarkus.datasource.db-version: https://quarkus.io/guides/hibernate-orm#hibernate-dialect-supported-databases
A PR to simply add a flag for this configuration in Quarkus (e.g.
quarkus.hibernate-orm.start-offline) could fix your whole use case.
Should I create one? Because that sounds like 5 minutes of coding...
A PR to simply add a flag for this configuration in Quarkus (e.g.
quarkus.hibernate-orm.start-offline) could fix your whole use case.Should I create one? Because that sounds like 5 minutes of coding...
That would be much appreciated! I'm not sure it will take 5 minutes, but I'd love to be proved wrong, and it's certainly short-ish.
If it's your first time contributing, you'll find all instructions in CONTRIBUTING.md, and I'll gladly help you along the way -- feel free to ping me here or on Zulip (though I'll be offline starting this evening until next Monday).
We'd need:
- A
start-offlinesetting, probably inio.quarkus.hibernate.orm.runtime.HibernateOrmRuntimeConfigPersistenceUnit.HibernateOrmConfigPersistenceUnitDatabase. - Code that turns this setting into
hibernate.boot.allow_jdbc_metadata_access=*. Probably inio.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider#injectRuntimeConfiguration. - Adjusting defaults and sanity checks:
io.quarkus.hibernate.orm.runtime.HibernateOrmRuntimeConfigPersistenceUnit.HibernateOrmConfigPersistenceUnitDatabase#versionCheckEnabledshould default tofalsewhen asked to start offline, and lead to an exception with a clear message when it's explicitly set totruewhile starting offline.io.quarkus.hibernate.orm.runtime.HibernateOrmRuntimeConfigPersistenceUnit.HibernateOrmConfigPersistenceUnitSchemaManagement#strategyshould default tononewhen asked to start offline, and lead to an exception with a clear message when it's explicitly set to anything else while starting offline.- Code that automatically sets the schema management strategy when using dev services should probably be skipped when Hibernate ORM is configured to start offline.
- Maybe more, but I can't think of anything else. The above would be a start, I'm sure we'll get confused bug reports if not.
- A test. You may want to take inspiration from
io.quarkus.hibernate.search.orm.elasticsearch.test.offline.StartOfflineTest-- that's for Hibernate Search, so not the same component, but testing should be similar: configure an explicit JDBC URL that points nowhere (to simulate an offline DB), configure Hibernate ORM to start offline, check the app starts, and check explicit schema management fails just to be sure the DB really is offline.
@yrodiere I created a basic PR at https://github.com/quarkusio/quarkus/pull/47695 that should cover points 1-2.
All other points are bit too advanced for me as I e.g. don't know how I'm supposed to set a config value ("should default to none when asked to start offline") when there is only an interface available...
Couldn't test this PR so far with my setup so it might also be an idea that someone does that ;)
Thanks again for the contribution. As explained on the PR, though, we need tests.
Since the PR hasn't moved for 3 weeks, I'm reassigning to @lucamolteni who will take that work (and another related one), then add tests on top of it. See https://github.com/quarkusio/quarkus/issues/13522#issuecomment-2890888283 for more information.
Thanks again for the contribution. As explained on the PR, though, we need tests.
Since the PR hasn't moved for 3 weeks, I'm reassigning to @lucamolteni who will take that work (and another related one), then add tests on top of it. See #13522 (comment) for more information.
I've opened a Draft PR based on the ORM 7 branch https://github.com/quarkusio/quarkus/pull/48130


