在多租戶的情況,如果將所有租戶的數據保存在同一數據庫同一schama內,這會給數據的管理和安全帶來很大風險,雖然這樣做的成本最佳。
另一種方式是將不同的租戶保存在不同的schama內,這樣一個租戶對應一個schema,這樣管理比較方便,出現問題風險也比較小點,實現這樣的方式就會有多個數據源,
因爲所有的租戶對就的都一同一個應用實體,它們只是應用不同的數據庫。所以我們就要在每個用戶在操作應用系統時,爲這個用戶設置正確的數據源來對數據庫進行操作,
spring 爲我們提供了數據源路由的抽象類,AbstractRoutingDataSource。繼承這個抽象類爲,首先初始化所有租戶的數據源,然後對過protected Object determineCurrentLookupKey() 方法返回當前租戶的數據源。達到對數據庫的操作。
下面簡單說明下AbstractRoutingDataSource類:
首先看下AbstractRoutingDataSource類結構,繼承了AbstractDataSource
- public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
- }
既然是AbstractDataSource,當然就是javax.sql.DataSource的子類,於是我們自然地回去看它的getConnection方法:
- public Connection getConnection() throws SQLException {
- return determineTargetDataSource().getConnection();
- }
原來奧妙就在determineTargetDataSource()裏:
- /**
- * Retrieve the current target DataSource. Determines the
- * {@link #determineCurrentLookupKey() current lookup key}, performs
- * a lookup in the {@link #setTargetDataSources targetDataSources} map,
- * falls back to the specified
- * {@link #setDefaultTargetDataSource default target DataSource} if necessary.
- * @see #determineCurrentLookupKey()
- */
- protected DataSource determineTargetDataSource() {
- Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
- Object lookupKey = determineCurrentLookupKey();
- DataSource dataSource = (DataSource) this.resolvedDataSources.get(lookupKey);
- if (dataSource == null) {
- dataSource = this.resolvedDefaultDataSource;
- }
- if (dataSource == null) {
- throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
- }
- return dataSource;
- }
這裏用到了我們需要進行實現的抽象方法determineCurrentLookupKey(),該方法返回需要使用的DataSource的key值,然後根據這個key從resolvedDataSources這個map裏取出對應的DataSource,如果找不到,則用默認的resolvedDefaultDataSource
- <bean id="onlineDynamicDataSource" class="com.xx.stat.base.dynamic.DynamicDataSource">
- <property name="targetDataSources">
- <map key-type="java.lang.String">
- <entry key="xx" value-ref="dataSourceXX"/>
- <entry key="yy" value-ref="dataSourceYY"/>
- </map>
- </property>
- <property name="defaultTargetDataSource" ref="dataSource"/>
- </bean>
觀察上面的配置文件,發現我們配置的是targetDataSources和defaultTargetDataSource