Rest (Spring boot和Spring data jpa)如何动态更改数据源?

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

对于我的新项目,我构建了一个基本的RESTAPI,以便在客户端请求时返回数据。但是,客户机必须选择自己选择的数据库作为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的文章,但我不知道如何使用它。

没有测试过它,只是简单地浏览了一下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(东西);
}
}
请看这里: