Настройка трех источников данных; Два, которые не меняются, и один, который требует диспетчера источников данных - PullRequest
0 голосов
/ 04 марта 2020

Я пытаюсь настроить «три» класса источника данных в приложении Spring. Я успешно настроил два, но «третий», который я хочу настроить на неопределенное количество источников данных, доставляет мне проблемы.

Вот моя идея (неработающий V1):

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "referenceEntityManager",
    transactionManagerRef = "referenceTransactionManager",
    basePackages = "com.tes.domain.repositories.reference.repositories")
@PropertySource("file:${C:\\Some\\Path\\file.properties")
public class ManyConfigurations{

@Autowired
EnvironmentHelper environmentHelper;
//derived from primary datasource below
@Autowired
IReferenceRepo referenceRepo;

private DataSourceManager dataSourceManager = new DataSourceManager();

public DataSource makeDataSource(String name) throws PropertyVetoException {
    ComboPooledDataSource ds = new ComboPooledDataSource();
    ds.setDriverClass(environmentHelper.getEnvironment().getProperty("base_datasource_driver"));
    ds.setJdbcUrl(environmentHelper.getEnvironment().getProperty("base_datasource_url") +";databaseName=reference" + name);
    ds.setUser(environmentHelper.getEnvironment().getProperty("base_datasource_username"));
    ds.setPassword(environmentHelper.getEnvironment().getProperty("base_datasource_password"));
    ds.setAcquireIncrement(5);
    ds.setAcquireRetryAttempts(10);
    ds.setAcquireRetryDelay(5000);
    ds.setInitialPoolSize(52);
    ds.setMaxIdleTime(3600);
    ds.setMaxIdleTimeExcessConnections(300);
    ds.setMinPoolSize(52);
    ds.setMaxPoolSize(125);
    ds.setNumHelperThreads(6);
    ds.setUnreturnedConnectionTimeout(0);
    return ds;
}

@Bean(name = "referenceDataSource")
public DataSourceManager dataSource() throws PropertyVetoException {
    List<Reference> references= referenceRepo.findAll();
    if (references != null) {
        for (Reference r : references) {
            dataSourceManager.add(r.getId().toString(), makeDataSource(r.getId().toString()));
        }
    }
    if (!references.isEmpty()) {
        dataSourceManager.switchDataSource(references.get(0).getId().toString());
    }
    return dataSourceManager;
}


@Bean(name = "referenceEntityManager")
public LocalContainerEntityManagerFactoryBean getReferenceEntityManager(DataSourceManager dataSourceManager) throws PropertyVetoException {
    for (Map.Entry<String, DataSource> entry : dataSourceManager.getDataSources().entrySet()) {
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(entry.getValue());
        em.setPackagesToScan(new String[]{"com.tes.domain.model.reference.models"});
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalJpaProperties());
        em.setPersistenceUnitName("reference" + entry.getKey());
        dataSourceManager.addEntityManager(entry.getKey(), em);
    }
    dataSourceManager.updateToMatch();
    return dataSourceManager.getEntityManager();
}

Properties additionalJpaProperties(){
    Properties properties = new Properties();
    return properties;
}

@Bean(name = "referenceTransactionManager")
public JpaTransactionManager referenceTransactionManager(DataSourceManager dataSourceManager) throws PropertyVetoException {
    for (Map.Entry<String, LocalContainerEntityManagerFactoryBean> entry : dataSourceManager.getEntityManagers().entrySet()) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setDataSource(dataSourceManager.getDataSources().get(entry.getKey()));
        transactionManager.setEntityManagerFactory(entry.getValue().getObject());
        transactionManager.setPersistenceUnitName("reference" + entry.getKey());
        dataSourceManager.addTransactionalManager(entry.getKey(), transactionManager);
    }
    dataSourceManager.updateToMatch();
    return dataSourceManager.getTransactionManager();

}
}

Мой менеджер источников данных выглядит так:

public class DataSourceManager implements DataSource {

private Map<String, DataSource> dataSources = new HashMap<>();
private Map<String, LocalContainerEntityManagerFactoryBean> entityManagers = new HashMap<>();
private Map<String, JpaTransactionManager> transactionalManagers = new HashMap<>();
private DataSource dataSource;
private LocalContainerEntityManagerFactoryBean entityManager;
private JpaTransactionManager transactionManager;

public DataSourceManager() {
}

public DataSourceManager(DataSource dataSource) {
    this.dataSource = dataSource;
}

public void add(String name, DataSource dataSource) {
    dataSources.put(name, dataSource);
}

public void addEntityManager(String name, LocalContainerEntityManagerFactoryBean entityManager) {
    entityManagers.put(name, entityManager);
}

public void addTransactionalManager(String name, JpaTransactionManager transactionManager) {
    transactionalManagers.put(name, transactionManager);
}

public void switchDataSource(String name) {
    dataSource = dataSources.get(name);
    entityManager = entityManagers.get(name);
    transactionManager = transactionalManagers.get(name);
}


public void updateToMatch() {
    for (Map.Entry<String, DataSource> entry : dataSources.entrySet()) {
        if (entry.getValue().equals(dataSource)) {
            String name = entry.getKey();
            try {
                entityManager = entityManagers.get(name);
                transactionManager = transactionalManagers.get(name);
            } catch (Exception e) {

            }
        }
    }
}

@Override
public PrintWriter getLogWriter() throws SQLException {
    return dataSource.getLogWriter();
}

@Override
public void setLogWriter(PrintWriter out) throws SQLException {
    dataSource.setLogWriter(out);
}

@Override
public void setLoginTimeout(int seconds) throws SQLException {
    dataSource.setLoginTimeout(seconds);
}

@Override
public int getLoginTimeout() throws SQLException {
    return dataSource.getLoginTimeout();
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    return dataSource.getParentLogger();
}

@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
    return dataSource.unwrap(iface);
}

@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
    return dataSource.isWrapperFor(iface);
}

@Override
public Connection getConnection() throws SQLException {
    return dataSource.getConnection();
}

@Override
public Connection getConnection(String username, String password) throws SQLException {
    return dataSource.getConnection(username, password);
}

public Map<String, DataSource> getDataSources() {
    return dataSources;
}

public Map<String, LocalContainerEntityManagerFactoryBean> getEntityManagers() {
    return entityManagers;
}

public Map<String, JpaTransactionManager> getTransactionalManagers() {
    return transactionalManagers;
}

public DataSource getDataSource() {
    return dataSource;
}

public LocalContainerEntityManagerFactoryBean getEntityManager() {
    return entityManager;
}

public JpaTransactionManager getTransactionManager() {
    return transactionManager;
}

}

У меня есть несколько идей о том, что я хотел бы сделать. По сути, я хотел бы отобразить их активную предпочитаемую базу данных, на которую ссылаются, и предварительно сконфигурировать каждую базу данных, на которую ссылаются, в приложении весенней загрузки. Мы перезапускаем Tomcat каждый раз, когда добавляем новую базу данных (не большая проблема), и будет конечная точка для переключения предпочитаемой пользователем базы данных.

Звучит хорошо в гипотезе. Большое препятствие, с которым я столкнулся, было, когда я использовал:

@EnableJpaRepositories(entityManagerFactoryRef = "referenceEntityManager",
        transactionManagerRef = "referenceTransactionManager",
        basePackages = "com.tes.domain.repositories.reference.repositories")

Я столкнулся с проблемой, что настраивался только мой последний возвращенный JpaTransactionManager, и у меня не было возможности «переключать» источники данных как мой класс DataSourceManager. должен быть в состоянии сделать.

Я пытаюсь сказать, можно ли настроить расширенное количество JpaTransactionManager и переключаться между ними так же, как я переключаюсь между источником данных?

В качестве альтернативы, есть ли способ переключения между источниками данных, который также изменяет источники моего менеджера транзакций?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...