Dynamic datasource routing - DataSource router not initialized

蹲街弑〆低调 提交于 2019-12-06 10:15:31

问题


I'm referring to this article, in which we can use the AbstractRoutingDataSource from Spring Framework to dynamically change the data source used by the application. I'm using Mybatis (3.3.0) with Spring (4.1.6.RELEASE). I want to switch to the backup database if exception occurs while getting data from main db. In this example, i have used hsql and mysql db.

RoutingDataSource:

public class RoutingDataSource extends AbstractRoutingDataSource {

@Override
protected Object determineCurrentLookupKey() {
    return DataSourceContextHolder.getTargetDataSource();
 }
}

DataSourceContextHolder:

public class DataSourceContextHolder {

private static final ThreadLocal<DataSourceEnum> contextHolder = new ThreadLocal<DataSourceEnum>();

public static void setTargetDataSource(DataSourceEnum targetDataSource) {
    contextHolder.set(targetDataSource);
}

public static DataSourceEnum getTargetDataSource() {
    return (DataSourceEnum) contextHolder.get();
}

public static void resetDefaultDataSource() {
    contextHolder.remove();
 }
}

ApplicationDataConfig:

@Configuration
@MapperScan(basePackages = "com.sample.mapper")
@ComponentScan("com.sample.config")
@PropertySource(value = {"classpath:app.properties"},
                ignoreResourceNotFound = true)
public class ApplicationDataConfig {

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    PropertySourcesPlaceholderConfigurer configurer =
        new PropertySourcesPlaceholderConfigurer();
    return configurer;
}

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    RoutingDataSource routingDataSource = new RoutingDataSource();
    routingDataSource.setDefaultTargetDataSource(dataSource1());
    Map<Object, Object> targetDataSource = new HashMap<Object, Object>();
    targetDataSource.put(DataSourceEnum.HSQL, dataSource1());
    targetDataSource.put(DataSourceEnum.BACKUP, dataSource2());
    routingDataSource.setTargetDataSources(targetDataSource);
    sessionFactory.setDataSource(routingDataSource);
    sessionFactory.setTypeAliasesPackage("com.sample.common.domain");

    sessionFactory.setMapperLocations(
        new PathMatchingResourcePatternResolver()
            .getResources("classpath*:com/sample/mapper/**/*.xml"));

    return sessionFactory;
}

@Bean
public DataSource dataSource1() {
    return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript(
            "classpath:database/app-hsqldb-schema.sql").addScript(
            "classpath:database/app-hsqldb-datascript.sql").build();
}


@Bean
public DataSource dataSource2() {
    PooledDataSourceFactory pooledDataSourceFactory = new PooledDataSourceFactory();
    pooledDataSourceFactory.setProperties(jdbcProperties());
    return pooledDataSourceFactory.getDataSource();
}

@Bean
protected Properties jdbcProperties() {
    //Get the data from properties file
    Properties jdbcProperties = new Properties();
    jdbcProperties.setProperty("url", datasourceUrl);
    jdbcProperties.setProperty("driver", datasourceDriver);
    jdbcProperties.setProperty("username", datasourceUsername);
    jdbcProperties.setProperty("password", datasourcePassword);
    jdbcProperties.setProperty("poolMaximumIdleConnections", maxConnectionPoolSize);
    jdbcProperties.setProperty("poolMaximumActiveConnections", minConnectionPoolSize);

    return jdbcProperties;
}
}

Client:

 @Autowired
 private ApplicationMapper appMapper;

public MyObject getObjectById(String Id) {
    MyObject myObj = null;
    try{
        DataSourceContextHolder.setTargetDataSource(DataSourceEnum.HSQL);
        myObj = appMapper.getObjectById(Id);
    }catch(Throwable e){
        DataSourceContextHolder.setTargetDataSource(DataSourceEnum.BACKUP);
        myObj = appMapper.getObjectById(Id);  
    }finally{
        DataSourceContextHolder.resetDefaultDataSource();
    }
    return getObjectDetails(myObj);
}

I'm getting the following exception

### Error querying database.  Cause: java.lang.IllegalArgumentException: DataSource router not initialized

However i'm able to get things working if i'm using only one db at a time, this means there is no issue with data source configuration.


回答1:


Can you try this last line once (in same order) :-

targetDataSource.put(DataSourceEnum.HSQL, dataSource1());
targetDataSource.put(DataSourceEnum.BACKUP, dataSource2());
routingDataSource.setTargetDataSources(targetDataSource);

routingDataSource.afterPropertiesSet();



回答2:


I got the same issue and found a solution using the SchemaExport class of hibernate. For each DataSourceEnum you can manually initialize the datasource.

here is my detailed answer to my own issue discription



来源:https://stackoverflow.com/questions/32580188/dynamic-datasource-routing-datasource-router-not-initialized

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!