两个互斥数据源上的Spring数据JPA

时间:2019-04-10 18:30:06

标签: java spring-boot jpa

我的应用程序有两个包含相同架构的MYSQL数据库,但是两个数据库中的数据都是唯一的(分布式)。 就像假设订单号是偶数一样,它将转到第一个数据库,否则将转到第二个数据库。

# 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);
    }

}

如果entityManagers拥有自己的jpa存储库,则可以使用。但是在我的情况下,两个entityManagers都具有相同的jpa存储库。 有人可以帮助我吗,有什么方法可以满足我的要求?

1 个答案:

答案 0 :(得分:0)

我认为您可以像这样创建基础存储库(未用@Repository注释)

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

然后您可以使用两个存储库来扩展基本存储库界面

@Repository
public interface User1Repository extends UserRepository {
}

@Repository
public interface User2Repository extends UserRepository {
}

基础存储库将使您可以在一处定义所有方法。 在使用中,您必须像这样组合两个存储库:

@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());
    }

}