2016-09-29 55 views
0

對於我的新項目,我構建了一個基本的rest api來根據客戶端請求返回數據。但是,客戶端必須選擇他選擇的數據庫作爲HTTP GET請求的參數。(Spring-boot&Spring data jpa)如何即時更改數據源?

現在我的問題是,我不知道如何做到這一點與Sprint啓動。我知道我們可以提供許多不同的數據源,但是如何在檢查請求後更改所需的數據源?

這裏是我的數據源配置,效果很好:

@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

請看看這裏:[動態數據庫連接切換和數據庫路由的應用程序多租戶](http://springrules.blogspot.com/2017/08/dynamic-database-co nnection-switching.html) – vRaptor

回答

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其他方法。

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