简体   繁体   中英

Spring data jpa on two mutually exclusive datasources

My application has two MYSQL databases which contains same schema but the data is unique(distributed) in both of them. Like if consider the order number is even it will go to first database else will go to the second.

# DataSource1
spring.first.datasource.jdbcUrl=jdbc:mysql://localhost:3306/mysqlone?autoReconnect=true&useSSL=false
spring.first.datasource.username=root
spring.first.datasource.password=password
spring.first.datasource.driver-class-name=com.mysql.jdbc.Driver

# DataSource2
spring.second.datasource.jdbcUrl=jdbc:mysql://localhost:3306/mysqltwo?autoReconnect=true&useSSL=false
spring.second.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.second.datasource.username=root
spring.second.datasource.password=password

# JPA / HIBERNATE
spring.first.jpa.show-sql=true
spring.first.jpa.hibernate.ddl-auto=none
spring.first.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

spring.second.jpa.show-sql=true
spring.second.jpa.hibernate.ddl-auto=none
spring.second.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
@Entity
@Table(name="USER_TB")
public class User {
    @Id
    private int id;
    private String name;    
}
@Repository
public interface UserRepository extends JpaRepository<User, Integer>{
}
@Configuration
@EnableJpaRepositories(basePackages = {"com.multi.ds.api.repo"},
entityManagerFactoryRef = "ds1EntityManager",
transactionManagerRef = "ds1TransactionManager")
public class DatabaseOne {
    @Autowired
    private Environment env;

    @Bean
    public DataSource ds1Datasource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
        dataSource.setDriverClassName(env.getProperty("spring.first.datasource.driver-class-name"));    
        dataSource.setUrl(env.getProperty("spring.first.datasource.jdbcUrl"));  
        dataSource.setUsername(env.getProperty("spring.first.datasource.username"));        
        dataSource.setPassword(env.getProperty("spring.first.datasource.password"));
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean ds1EntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(ds1Datasource());
        em.setPackagesToScan(new String[] { "com.multi.ds.api.model" });
        em.setPersistenceUnitName("ds1EntityManager");
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.dialect", env.getProperty("spring.first.jpa.properties.hibernate.dialect"));
        properties.put("hibernate.show-sql", env.getProperty("spring.first.jpa.show-sql"));
        em.setJpaPropertyMap(properties);
        em.afterPropertiesSet();
        return em;
    }

    @Bean
    public PlatformTransactionManager ds1TransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(ds1EntityManager().getObject());
        return transactionManager;
    }

}
@EnableJpaRepositories(basePackages = {"com.multi.ds.api.repo"},
entityManagerFactoryRef = "ds2EntityManager",
transactionManagerRef = "ds2TransactionManager")
public class DatabaseTwo {

    @Autowired
    private Environment env;

    @Bean
    public DataSource ds2Datasource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("spring.second.datasource.driver-class-name"));   
        dataSource.setUrl(env.getProperty("spring.second.datasource.jdbcUrl"));     
        dataSource.setUsername(env.getProperty("spring.second.datasource.username"));       
        dataSource.setPassword(env.getProperty("spring.second.datasource.password"));
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean ds2EntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(ds2Datasource());
        em.setPackagesToScan(new String[] { "com.multi.ds.api.model" });
        em.setPersistenceUnitName("ds2EntityManager");
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.dialect", env.getProperty("spring.second.jpa.properties.hibernate.dialect"));
        properties.put("hibernate.show-sql", env.getProperty("spring.second.jpa.show-sql"));
        em.setJpaPropertyMap(properties);
        em.afterPropertiesSet();
        return em;
    }

    @Bean
    public PlatformTransactionManager ds2TransactionManager() {

        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(ds2EntityManager().getObject());
        return transactionManager;
    }

}
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional("${txManager}")
    public List<User> getAll(){
        return userRepository.findAll();
    }

}
@SpringBootApplication
@EnableAutoConfiguration(exclude = { 
        DataSourceAutoConfiguration.class, 
        DataSourceTransactionManagerAutoConfiguration.class, 
        HibernateJpaAutoConfiguration.class })
@RestController

public class SpringBootMultiDs1Application {

    @Autowired
    UserService userService;

    @RequestMapping(value = "/all", method = RequestMethod.GET)
    public List<User> getAll(Long orderNumber){
        //if orderNumber is even I need Users from Datasource1 else from Datasource2 USER_TB table
        return userService.getAll();
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringBootMultiDs1Application.class, args);
    }

}

If the entityManagers have there own jpa repositories it would have worked.But in my case both entityManagers have same jpa repositories. Can someone help me is there any way to achieve this or any alternative ways to support my requirement?

I think you can create a base repository (not annotated with @Repository ) like that:

public interface UserRepository extends JpaRepository<User, Integer> {
}

Then you can two repositories that extends the base repository interface

@Repository
public interface User1Repository extends UserRepository {
}

@Repository
public interface User2Repository extends UserRepository {
}

The base repository will allow you to define all methods in one place. And in service, you have to combine both repositories like that:

@Service
public class UserService {

    private final User1Repository user1Repository;

    private final User2Repository user2Repository;

    @Autowired
    public UserService(User1Repository user1Repository, User2Repository user2Repository) {
        this.user1Repository = user1Repository;
        this.user2Repository = user2Repository;
    }

    @Transactional(readOnly = true)
    public List<User> getAll(){
        return Stream.concat(user1Repository.findAll().stream(), user2Repository.findAll().stream()).collect(Collectors.toList());
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM