Rest (Spring boot和Spring data jpa)如何动态更改数据源?
对于我的新项目,我构建了一个基本的RESTAPI,以便在客户端请求时返回数据。但是,客户机必须选择自己选择的数据库作为HTTP GET请求的参数 现在我的问题是,我不知道如何使用Sprint boot做到这一点。我知道我们可以提供许多不同的数据源,但是在检查请求之后,我们如何更改所需的数据源呢 这是我的数据源配置,运行良好:Rest (Spring boot和Spring data jpa)如何动态更改数据源?,rest,spring-boot,datasource,spring-data-jpa,Rest,Spring Boot,Datasource,Spring Data Jpa,对于我的新项目,我构建了一个基本的RESTAPI,以便在客户端请求时返回数据。但是,客户机必须选择自己选择的数据库作为HTTP GET请求的参数 现在我的问题是,我不知道如何使用Sprint boot做到这一点。我知道我们可以提供许多不同的数据源,但是在检查请求之后,我们如何更改所需的数据源呢 这是我的数据源配置,运行良好: @Configuration public class DataSourceConfig { @Bean @Primary @Configurat
@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的文章,但我不知道如何使用它。没有测试过它,只是简单地浏览了一下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;
}
}
}
如果您需要类中的其他行为,您可能需要重写其他方法。它应该遵循以下原则:
// 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();
}
}
//创建类来保存选择数据源的“键”
//您将根据GET或POST请求确定它
//它使用ThreadLocal,因此每个请求都会有一个线程
公共类SomeRequestContext{
private static ThreadLocal keyToChoseDataSource=new ThreadLocal();
公共静态无效setKeyToChoseDataSource(对象键){
keyToChoseDataSource.set(键);
}
公共静态对象getKeyToChoseDataSource(){
返回keyToChoseDataSource.get();
}
}
//这是您的AbstractRoutingDataSource实现,它将
//从上面的上下文类中获取密钥
公共类多数据源扩展了AbstractRoutingDataSource{
@凌驾
受保护的对象确定当前查找键(){
返回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;
}
//在这里,您只需将所有数据源放入AbstractRoutingDataSource实现中即可
@豆子
@初级的
公共数据源数据源(){
MultiDataSource dataSource=新的MultiDataSource();
setDefaultTargetDataSource(someDefaultDataSource());
Map resolvedDataSources=新HashMap();
resolvedDataSources.put(“dev21”,buildDataSource21());
resolvedDataSources.put(“dev22”,buildDataSource22());
//……等等。。。
dataSource.setTargetDataSources(resolvedDataSources);
dataSource.AfterPropertieSet();
返回数据源;
}
在你的控制器里
@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);
}
}
@控制器
公共类控制器{
@自动连线
私有存储库;
@RequestMapping(path=“/path”,method=RequestMethod.POST)
公共响应性createStuff(){
TenantContext.setCurrentTenant(租户名称);
SomeRequestContext.setKeyToChoseDataSource(getKeyFromRequest());//这将是dev21或dev22或其他类型
SomeStuff=新的SomeStuff();
yourRepository.save(stuff);//将保存到正确的数据库中
返回应答。ok(东西);
}
}
请看这里: