spring動態創建數據源
項目業務,在程序的運行過程中,可能會存在新的數據庫添鏈接加進來,從新數據庫鏈接中讀取數據。
spring為多數據源提供了一個抽象類AbstractRoutingDataSource,該類中只有一個抽象方法determineCurrentLookupKey()需要由我們實現。
假設我們創建一個類DynimaticDataSource,繼承AbstractRoutingDataSource,並重寫determineCurrentLookupKey()方法。
spring啟動初始化DynimaticDataSource:
1、可以通過spring的自動註入,對AbstractRoutingDataSource類註入相應的屬性,註入屬性不是必須的,可以通過繼承後重寫方法來重設對這些屬性的調用。
2、註入後spring會執行DynimaticDataSource中的protected方法afterPropertiesSet(),該方法先判斷屬性targetDataSources不能為null,否則拋出異常"Property ‘targetDataSources‘ is required"。然後將該屬性(類型為map<object,object>)的值全部轉換到屬性resolvedDataSources(類型為map<Object, DataSource>)中去。如果屬性defaultTargetDataSource不為null,將其轉換為DataSource類型並賦值給屬性defaultTargetDataSource。
經過以上處理後,屬性resolvedDataSources中會被存放我們添加的數據源,該屬性是一個map集合,key為Object類型,value為數據源。
使用DynimaticDataSource類:
1、調用該類的public方法getConnection()來獲取連接。
2、getConnection被重寫,方法中會先調用protected方法determineTargetDataSource()。該方法先判斷屬性resolvedDataSources不為null,否則拋出異常"DataSource router not initialized"。然後調用由子類重寫的抽象方法determineCurrentLookupKey()獲取dataSource在resolvedDataSources中對應的key。
3、根據key從resolvedDataSources中獲取數據源,如果resolvedDataSources中不存在,再判斷lenientFallback為true(默認為true,可以設置)或key為null,返回默認數據源resolvedDefaultDataSource。否則拋出異常"Cannot determine target DataSource for lookup key [" + key+ "]"。
4、調用獲取數據源的getConnection()方法獲取連接。
在初始化時指定多數據源案例代碼:
1、創建一個類DynimaticDataSource,繼承AbstractRoutingDataSource,並重寫determineCurrentLookupKey()方法。該方法負責判斷當前線程使用哪一種數據源。這是最簡單的一種實現方法,不重寫任何非抽象方法。
public class DynamicDatasource extends AbstractRoutingDataSource{ private static Map<Object, Object> targetDataSources; protected DruidDataSource dataSource; @Override protected String determineCurrentLookupKey() {
//指定使用哪個數據源 return DataSourceUtils.getDbtype(); } }
2、srping配置文件(部分)
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="maxActive" value="50" /><!-- 最大連接池數 --> <property name="minIdle" value="5" /><!-- 最小連接池數 --> </bean> <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="${jdbc.url2}" /> <property name="username" value="${jdbc.username2}" /> <property name="password" value="${jdbc.password2}" /> <property name="driverClassName" value="${jdbc.driver}" /> <property name="maxActive" value="50" /><!-- 最大連接池數 --> <property name="minIdle" value="5" /><!-- 最小連接池數 --> </bean> <bean id="multDataSource" class="com.ftpSystem.dao.DynamicDatasource"> <property name="targetDataSources"> <map > <entry value-ref="dataSource" key="masterDataSource"></entry> <entry value-ref="dataSource2" key="yangDataSource"></entry> </map> </property>
<property name="defaultTargetDataSource" ref="dataSource"></property>
</bean>
3、使用數據源,我這裏使用jdbcTemple,可以使用其他持久層框架,方式同單數據源配置一致。
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="multDataSource"></property> </bean>
4、切換數據源類
public class DataSourceUtils { private static final ThreadLocal<String> local = new ThreadLocal<String>(); public static String getDbtype() { return local.get(); } public static void setDbtype(String dbtype) { local.set(dbtype); } public static void clear() { local.remove(); } }
5、客戶端代碼
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-dao.xml") public class TestDao { @Autowired private JdbcTemplate jdbcTemplate; @Test public void Test(){ System.out.println("ok"); int i = (Integer) jdbcTemplate.queryForObject("select count(*) from t_gg_zsdw", Integer.class); System.out.println("i="+i); DataSourceUtils.setDbtype("dataSource2");//切換數據源至dataSource2 i = (Integer) jdbcTemplate.queryForObject("select count(*) from t_gg_zsdw", Integer.class); System.out.println("i="+i); } }
由於我們已經在spring的配置文件中指定了屬性defaultTargetDataSource,因此程序會默認使用該數據源。然後我們執行一次後切換為dataSource2,之後的執行會改為使用dataSource2的數據源。
以上方式可以對程序配置多數據源,但是不方便之處在程序初始化之時就指定所有的數據源,無法運行時添加。
程序動態配置多數據源:
該方式與上一種的區別在於重寫AbstractRoutingDataSource類的子類DynimaticDataSource
下班了,明天繼續
spring動態創建數據源