Thursday, February 16, 2023

Spring boot multi-tenancy connection


 

I know there are a lot of posts on spring boot multi-tenancy, but I have to post this since I just used the multi-tenancy connection in one of my projects.

I will keep it simple, basically, there are 3 parts to achieving the multi-tenancy connection.


EntityManager
DataSource
TransactionManager

We can have as many connections as required to multiple schemas or databases, each connection should have its own above-configuration objects, In the below example, we are trying to fetch the list of Product from schema1 and list of User from schema 2

application.properties

spring.datasource.jdbcUrl=jdbc:mysql://127.0.0.1:3306/schema_1
spring.datasource.username=username
spring.datasource.password=password

spring.second-datasource.jdbcUrl=jdbc:mysql://127.0.0.1:3306/schema_2
spring.second-datasource.username=username
spring.second-datasource.password=password
Configuration class for schema1

@Configuration
@PropertySource({"classpath:application.properties"})
@EnableJpaRepositories(basePackages = "dev.vinodkmr.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager")
public class PersistenceProductAutoConfiguration {
    @Autowired
    private Environment env;

    public PersistenceProductAutoConfiguration() {
        super();
    }


	//Entity Manager
    @Bean
    public LocalContainerEntityManagerFactoryBean productEntityManager() {
        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(productDataSource());
        em.setPackagesToScan("dev.vinodkmr.model.product");

        final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        final HashMap properties = new HashMap();
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        em.setJpaPropertyMap(properties);

        return em;
    }
    
    //DataSource
    @Bean
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource productDataSource() {
        return DataSourceBuilder.create().build();
    }

	//Transaction Manager
    @Bean
    public PlatformTransactionManager productTransactionManager() {
        final JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(productEntityManager().getObject());
        return transactionManager;
    }

}

Configuration class for schema2

@Configuration
@PropertySource({"classpath:application.properties"})
@EnableJpaRepositories(basePackages = "dev.vinodkmr.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager")
public class PersistenceUserAutoConfiguration {
    @Autowired
    private Environment env;

    public PersistenceUserAutoConfiguration() {
        super();
    }

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean userEntityManager() {
        final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(userDataSource());
        em.setPackagesToScan("dev.vinodkmr.model.user");

        final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        final HashMap properties = new HashMap();
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        em.setJpaPropertyMap(properties);

        return em;
    }

    @Bean
    @Primary
    @ConfigurationProperties(prefix="spring.second-datasource")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean
    public PlatformTransactionManager userTransactionManager() {
        final JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(userEntityManager().getObject());
        return transactionManager;
    }

}

We need to have the entities User and Product and respective repositories in a separate package as configured in the above configuration classes which are straightforward.

Please post your doubts in the comment section, if any.

Share:

0 comments:

Post a Comment