java - 动态数据源路由 - 数据源路由器未初始化

标签 java spring mybatis spring-jdbc spring-mybatis

我指的是这个 article ,其中我们可以使用 Spring Framework 中的 AbstractRoutingDataSource 来动态更改应用程序使用的数据源。我正在使用 Mybatis (3.3.0) 和 Spring (4.1.6.RELEASE)。如果从主数据库获取数据时发生异常,我想切换到备份数据库。在这个例子中,我使用了 hsql 和 mysql 数据库。

路由数据源:

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

应用数据配置:

@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

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

最佳答案

你能试一下这最后一行吗(以相同的顺序):-

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

routingDataSource.afterPropertiesSet();

关于java - 动态数据源路由 - 数据源路由器未初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32580188/

相关文章:

java - 如何从Java程序调用Oracle函数

java - 无法在 Android 内部存储中创建文件夹

java - spring 如何允许延迟加载?

mysql - 配置属性是未知属性

mysql - mysql函数中的ibatis和定界符

java - 使用 JSON 进行 Spring Security 错误处理

java - 将 java.lang.String 类型映射到 Postgres JSON 类型

java - 运行一个由try block 组成但没有catch或final子句的程序

java - 无法启动组件 [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/AuctionWebsite]]

java - 某些 Unix 命令失败并显示 "... not found",即使在启用 setPty 的情况下使用 JSch 通过 Java 执行