我指的是article,其中我们可以使用Spring Framework中的AbstractRoutingDataSource动态更改应用程序使用的数据源。我正在将Mybatis(3.3.0)与Spring(4.1.6.RELEASE)一起使用。如果要从主数据库获取数据时发生异常,我想切换到备份数据库。在此示例中,我使用了hsql和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;
}
}


客户:

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


我收到以下异常

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


但是,如果我一次只使用一个db,我就能使工作正常,这意味着数据源配置没有问题。

最佳答案

您能否以相同顺序尝试最后一行:-

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

routingDataSource.afterPropertiesSet();

09-11 18:43
查看更多