javaspring-bootjpaentitymanager

How to use specific EntityManagerFactory from multiple datasource configuration


I have a multiple datasource configuration and I'm trying to use the EntityManagerFactory of the secondary DB. Currently, when calling EntityManagerFactory, it only reference to primary DB configuration by retrieving error "Not an Entity". This is my configuration:

application.properties

spring.ds.datasource1.url=jdbc:postgresql:x
spring.ds.datasource1.username=user
spring.ds.datasource1.password=

spring.ds.datasource2.url=jdbc:postgresql:x
spring.ds.datasource2.username=user
spring.ds.datasource2.password=

Datasource 1 configuration:

@EnableJpaRepositories(basePackages = "eu.example", entityManagerFactoryRef = "ds1EntityManagerFactory", transactionManagerRef = "ds1TransactionManager")
@Configuration
public class Ds1DataSourceConfiguration {

    private static final String DS1_ENTITY_MANAGER_FACTORY = "ds1EntityManagerFactory";
    private static final String DS1_TRANSACTION_MANAGER = "ds1TransactionManager";

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.ds.datasource1")
    public DataSourceProperties ds1DataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean
    @ConfigurationProperties("spring.ds.datasource1")
    public DataSource ds1DataSource(DataSourceProperties properties) {
        return properties
                .initializeDataSourceBuilder()
                .build();
    }

    @Primary
    @Bean(name = DS1_ENTITY_MANAGER_FACTORY)
    public LocalContainerEntityManagerFactoryBean ds1EntityManagerFactoryBean(
            EntityManagerFactoryBuilder factoryBuilder, DataSource ds1Ds) {
        return factoryBuilder
                .dataSource(ds1Ds)
                .packages("eu.example.domain.entity.ds1")
                .build();
    }

    @Primary
    @Bean(name = DS1_TRANSACTION_MANAGER)
    public PlatformTransactionManager ds1TransactionManager(
            @Qualifier(DS1_ENTITY_MANAGER_FACTORY) LocalContainerEntityManagerFactoryBean managerFactoryBean) {
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        jpaTransactionManager.setEntityManagerFactory(managerFactoryBean.getObject());
        return jpaTransactionManager;
    }

}

Datasource 2 configuration is similar to the configuration above without Primary annotation

Service class:

@Service
public class TestService{

    private final EntityManagerFactory et2;
    
    ...

}

How can we reference et2 inside Service class to Datasource 2 EntityManagerFactory without using Persistence Unit?


Solution

  • Please refer EntityManager link

    An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed. The EntityManager API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities.

    Your configuration looks fine. refer this github repository link

    We can define entity, repository and invoke inthe service layer.

    Entity:

    package eu.example.domain.entity.ds1.model;
    @Entity
    public class Customer implements Serializable {
    // getter setters
    }
    

    Repository:

    package eu.example.domain.entity.ds1.repository;
    @Repository
    public interface CustomerRepository extends JpaRepository<Customer, Integer> {}
    

    Service:

    package eu.example.domain.entity.ds1.service;
    @Service
    public class CustomerServiceImpl implements CustomerService {
    
        @Autowired
        CustomerRepository customerRepository;
    
        @Override
        public List<ClientSetting> findClientDataSourceSettings() {
    
            return customerRepository.findAll();
        }
    
    }
    

    Alternative

    @Repository
    public class CustomerInfoRepository {
    
        @Autowired
        @Qualifier("ds1EntityManagerFactoryBean")
        private EntityManager entityManager;
    
        public List<Customer> getCustomerInfo() {
    
            Query query = entityManager.createNativeQuery(....);
            return  query.getResultList();
    
        }
    
        @Transactional("ds1TransactionManager")
        public void updateCustomerInfo(String name, Long id) {
            Query query = entityManager.createQuery(....);
             query.executeUpdate();
        }
    }