Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.lang.IllegalStateException: java.lang.NoSuchMethodError: error while configuring multiple database in springboot microservice project

I am trying to do a sample microservice which involves pulling data from multiple databases. And while configuring I am getting the Exception in thread "main" java.lang.IllegalStateException: java.lang.NoSuchMethodError: 'void org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension.registerLazyIfNotAlreadyRegistered error.

My application.properties file is like the following:

spring.datasource.primary.url=jdbc:postgresql://localhost:5432/firstdbsample
spring.datasource.primary.username=postgres
spring.datasource.primary.password=postgresql
spring.datasource.primary.driver-class-name=org.postgresql.Driver

spring.datasource.secondary.url=jdbc:postgresql://localhost:5432/seconddbsample
spring.datasource.secondary.username=postgres
spring.datasource.secondary.password=postgresql
spring.datasource.secondary.driver-class-name=org.postgresql.Driver

I kept all my model, controller and repository classes separately for separate packages, like the following:

com.multidb.primary.controller
com.multidb.primary.model
com.multidb.primary.repository
com.multidb.secondary.controller
com.multidb.secondary.model
com.multidb.secondary.repository

And created 2 separate configuration class for primary and secondary. I kept in com.multidb.config package with PrimaryConfig.java and SecondaryConfig.java

com.multidb.config.PrimaryConfig.java
com.multidb.config.SecondaryConfig.java

PrimaryConfig.java file:

@Configuration
@EnableJpaRepositories(
basePackages = "com.multidb.primary.repository",
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryConfig {

@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
}
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
        @Qualifier("primaryDataSource") DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setPackagesToScan(new String[] { "com.multidb.primary.model" });
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    return em;
}
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
        @Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) 
 {
    return new JpaTransactionManager(entityManagerFactory);
  }
}

SecondaryConfig.java:

@Configuration
@EnableJpaRepositories(
basePackages = "com.multidb.secondary.repository",
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager"
  )
  public class SecondaryConfig {

@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
        @Qualifier("secondaryDataSource") DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setPackagesToScan(new String[] { "com.multidb.secondary.model" });
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    return em;
}
@Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager secondaryTransactionManager(
        @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory);
}

}

Error like the following:

Correct the classpath of your application so that it contains a single, compatible version of org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension Exception in thread "main" java.lang.IllegalStateException: java.lang.NoSuchMethodError: 'void org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension.registerLazyIfNotAlreadyRegistered(java.util.function.Supplier, org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.String, java.lang.Object)'

Referred tutorials:

  • https://mookypoo.medium.com/spring-boot-connect-to-multiple-databases-4cd56773fbcc

  • https://www.baeldung.com/spring-data-jpa-multiple-databases

  • Spring Boot configure and use two data sources

POM.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.5.4</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.multidb</groupId>
<artifactId>MultiDb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>MultiDb</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
    <license/>
</licenses>
<developers>
    <developer/>
</developers>
<scm>
    <connection/>
    <developerConnection/>
    <tag/>
    <url/>
</scm>
<properties>
    <java.version>17</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
            <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>   
    
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

</project>

Update/Modification After Suggested Springboot Version 3.3.3

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.3</version> // changed from 3.5.4 to 3.3.3
    <relativePath/> <!-- lookup parent from repository -->
</parent>

Updated Error Message

Caused by: org.hibernate.service.spi.ServiceException: 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)

enter image description here

Can anyone suggest where I went in wrong in implementation or suggest good documentation for reference please?

like image 707
Mr.DevEng Avatar asked Mar 27 '26 09:03

Mr.DevEng


1 Answers

  1. To handle Unable to determine Dialect without JDBC metadata error, you have to add hibernate.dialect property to your LocalContainerEntityManagerFactoryBean through the setter:
em.setJpaPropertyMap(Map.of("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"));

After that, the error will be gone. Here are your edited full configs:

PrimaryConfig:

import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableJpaRepositories(
        basePackages = "com.multidb.primary.repository",
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        transactionManagerRef = "primaryTransactionManager"
)
public class PostgresConfig {

    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            @Qualifier("primaryDataSource") DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan("com.multidb.primary.model");
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        em.setJpaPropertyMap(Map.of(
                "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect", // dialect property
                "hibernate.hbm2ddl.auto", "update" // if you want to create tables from entities automatically
        ));

        return em;
    }

    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager primaryTransactionManager(
            @Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

SecondaryConfig

import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.Map;

@Configuration
@EnableJpaRepositories(
        basePackages =  "com.multidb.secondary.repository",
        entityManagerFactoryRef = "secondaryEntityManagerFactory",
        transactionManagerRef = "secondaryTransactionManager"
)
public class SecondaryConfig {

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
            @Qualifier("secondaryDataSource") DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();

        em.setDataSource(dataSource);
        em.setPackagesToScan("com.multidb.secondary.model");
        em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        em.setJpaPropertyMap(Map.of("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect")); // dialectProperty

        return em;
    }


    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager secondaryTransactionManager(
            @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}
  1. Besides, I also got an error after start that jdbcUrl is required with driverClassName.

This can be fixed by renaming both url property names to jdbc-url:

spring.datasource.primary.jdbc-url=jdbc:postgresql://localhost:5432/firstdbsample
spring.datasource.primary.username=postgres
spring.datasource.primary.password=postgresql
spring.datasource.primary.driver-class-name=org.postgresql.Driver

spring.datasource.secondary.jdbc-url=jdbc:postgresql://localhost:5432/seconddbsample
spring.datasource.secondary.username=postgres
spring.datasource.secondary.password=postgresql
spring.datasource.secondary.driver-class-name=org.postgresql.Driver

After that I got a running application without errors.

like image 159
Georgii Lvov Avatar answered Mar 29 '26 22:03

Georgii Lvov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!