Search code examples
springhibernatejpamulti-tenant

Spring Hibernate Multi Tenancy - avoid using default DataSource


We want to create a Spring Boot Hibernate multi-tenant project. We use a tenant-per-database approach. Expected that tenant ID will be extracted from headers during each request. There is no default tenant.

public class RoutingDataSourceProvider extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return TenantContext.getCurrentTenant(); // null by default
    }
}

During the start-up of the application, Hibernate is trying to initialize and the application finalizes with an error (what is expected) because there is no default DataSource.

getJdbcEnvironmentUsingJdbcMetadata:345 - HHH000342: Could not obtain connection to query metadata

java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null]

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided)

In there any way to avoid Hibernate initialization during the start-up?

We tried to find some solution but we drew a blank.


Solution

  • You can annotate the datasource, entity manager and transaction context beans with @Lazy. When the aplication is starting, the Hibernate errors appear but at the end it ends the starting process. Obviously, this depends on the way you have configured your beans in the application and the way it is started.

    Another option you can try is to configure a fake H2 in-memory datasource as a default for your RoutingDataSourceProvider, with the only purpose of avoid errors on the application start. The only problem in this case is that you need a way to free the resources allocated for the in-memory database after the application starts.

    See: How can I lazy create the EntityManagerFactory using Spring Data ORM/JPA?.