动态数据源路由 – 未初始化DataSource路由器
我指的是本文 ,我们可以使用Spring Framework中的AbstractRoutingDataSource动态更改应用程序使用的数据源。 我正在使用Mybatis(3.3.0)和Spring(4.1.6.RELEASE)。 如果从主数据库获取数据时发生exception,我想切换到备份数据库。 在这个例子中,我使用了hsql和mysql db。
RoutingDataSource :
public class RoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getTargetDataSource(); } }
DataSourceContextHolder :
public class DataSourceContextHolder { private static final ThreadLocal contextHolder = new ThreadLocal(); 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 targetDataSource = new HashMap(); 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); }
我收到以下exception
### 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();
我遇到了同样的问题,并找到了使用Hibernate的SchemaExport类的解决方案。 对于每个DataSourceEnum,您可以手动初始化数据源。
这是我对自己的问题描述的详细答案