对于我的新项目,我构建了一个基本的rest api来根据客户端请求返回数据。但是,客户端必须选择他选择的数据库,作为HTTP GET请求的参数。
现在我的问题是我不知道如何使用Sprint-boot做到这一点。我知道我们可以提供许多不同的数据源,但是如何在检查请求后更改所需的数据源?
这是我的数据源配置,效果很好:
@Configuration
public class DataSourceConfig {
@Bean
@Primary
@ConfigurationProperties(prefix="datasource.dev21")
public DataSource dev21DataSource() throws SQLException {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix="datasource.dev22")
public DataSource dev22DataSource() throws SQLException {
return DataSourceBuilder.create().build();
}
}
如果我想动态切换dev21和dev22,我该怎么办? 我已阅读有关 AbstractRoutingDataSource 类的文章,但我不知道如何使用它。
答案 0 :(得分:0)
没有经过测试,只是简单地浏览一下javadoc,这样的事情可能会起作用
@Configuration
public class DataSourceConfig {
public DataSource dev21DataSource() throws SQLException {
return DataSourceBuilder.create().build();
}
public DataSource dev22DataSource() throws SQLException {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource dataSource() throws SQLException {
RoutingDataSource ds = new RoutingDataSource();
DataSource ds21 = dev21DataSource();
DataSource ds22 = dev22DataSource();
Map dataSources = new HashMap();
dataSources.put(1, ds21);
dataSources.put(2, ds22);
ds.setDefaultTargetDataSource(ds21);
ds.setTargetDataSources(dataSources);
return ds;
}
}
public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
if (true) { //Should probably be some thread/tracaction/request safe check
return 1;
} else {
return 2;
}
}
}
如果您需要来自班级的其他行为,您可能需要override
其他方法。
答案 1 :(得分:0)
应该遵循以下方针:
// create class to hold the "key" to choose your datasource
// you will determine it from your GET or POST request
// It uses ThreadLocal so you will get one per each request
public class SomeRequestContext {
private static ThreadLocal<Object> keyToChoseDataSource = new ThreadLocal<>();
public static void setKeyToChoseDataSource(Object key) {
keyToChoseDataSource.set(key);
}
public static Object getKeyToChoseDataSource() {
return keyToChoseDataSource.get();
}
}
// This is you AbstractRoutingDataSource implementation that will
// get the key out of the context class above
public class MultiDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return SomeRequestContext.getKeyToChoseDataSource();
}
}
在您的配置中:
// Here you just put all your data sources into the AbstractRoutingDataSource implementation
@Bean
@Primary
public DataSource dataSource() {
MultiDataSource dataSource = new MultiDataSource();
dataSource.setDefaultTargetDataSource(someDefaultDataSource());
Map<Object,DataSource> resolvedDataSources = new HashMap<Object,DataSource>();
resolvedDataSources.put("dev21",buildDataSource21());
resolvedDataSources.put("dev22",buildDataSource22());
// ...etc...
dataSource.setTargetDataSources(resolvedDataSources);
dataSource.afterPropertiesSet();
return dataSource;
}
在您的控制器中
@Controller
public class YourController {
@Autowired
private YourRepository yourRepository;
@RequestMapping(path = "/path", method= RequestMethod.POST)
public ResponseEntity<?> createStuff() {
TenantContext.setCurrentTenant(tenantName);
SomeRequestContext.setKeyToChoseDataSource(getKeyFromRequest()); // this will be dev21 or dev22 or whatever
SomeStuff stuff = new SomeStuff();
yourRepository.save(stuff); // will be saved to the correct database
return ResponseEntity.ok(stuff);
}
}