SAAS系統的資料庫設計,動態資料來源動態切換
阿新 • • 發佈:2019-01-05
概念
資料來源:指的是一個具體的資料庫連線。例如 localhost:3306 或者 localhost:3306/sysdb
具體的資料庫:當前開啟的資料來源裡的資料庫物件的集合,一般稱之為database或者schema
這裡的SAAS系統考慮資料庫的擴充套件性,使用了多資料來源
考慮到一個數據源可以容納多個租戶的資料庫,因此1個數據源是要容納30到100個租戶資料庫的。
具體是參考 https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/aspect_dao
上邊這個git工程可以解決動態資料來源的建立,動態切換的問題。
動態建立資料來源的方法
動態切換資料來源依賴於DynamicRoutingDataSourceprivate DataSource getDataSource(String name) { DataSourceBuilder builder = DataSourceBuilder.create().driverClassName("com.mysql.jdbc.Driver"); if ("master".equals(name)) { builder.url("jdbc:mysql://localhost:3306/product_master?useSSL=false"); } else { builder.url("jdbc:mysql://localhost:3306/product_slave?useSSL=false"); } builder.username("root"); builder.password("root"); return builder.build(); }
以及在ThreadLocal裡儲存當前需要的資料來源名字,然後在合適的切面(service )方法執行前進行切換即可@Bean("dynamicDataSource") public DataSource dynamicDataSource() { DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(); Map<Object, Object> dataSourceMap = new HashMap<>(2); /*dataSourceMap.put("master", master()); dataSourceMap.put("slave", slave());*/ DataSource master = getDataSource("master"); dataSourceMap.put("master", master); dataSourceMap.put("slave", getDataSource("slave")); // Set master datasource as default dynamicRoutingDataSource.setDefaultTargetDataSource(master); // Set master and slave datasource as target datasource // 可動態路由的資料來源裡裝載了所有可以被路由的資料來源 dynamicRoutingDataSource.setTargetDataSources(dataSourceMap); // To put datasource keys into DataSourceContextHolder to judge if the datasource is exist DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSourceMap.keySet()); return dynamicRoutingDataSource; }
切換的方法
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* Set dynamic DataSource to Application Context 設定當前應用上下文所使用的資料來源
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
logger.info("Current DataSource is [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey();
}
}
還需要一個動態開啟具體的資料庫(schema)的方法。在dao方法裡的sql實際執行前進行攔截
mybatis攔截器
@Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}))
public class MyBatisInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Connection o = (Connection)invocation.getArgs()[0];
o.createStatement().executeQuery("use sys_0001");//schema 隔離 threalocal sys_0001
System.out.println(o.getClass());
Object result = invocation.proceed();
System.out.println("Invocation.proceed()");
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// TODO Auto-generated method stub
}
}