SpringMVC Mybatis配置多個(gè)數(shù)據(jù)源并切換代碼詳解
這篇文章主要介紹了SpringMVC Mybatis配置多個(gè)數(shù)據(jù)源并切換代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
最近公司一個(gè)項(xiàng)目需要連接兩個(gè)數(shù)據(jù)庫(kù)(A和B)操作,有的模塊查詢A庫(kù),有的模塊查詢B庫(kù),因此需要改造下,項(xiàng)目后臺(tái)用的是SpringMVC+Mybatis+MySQL架構(gòu),折騰了兩天后終于搞定了,在這里記錄過改造過程。
使用場(chǎng)景
多數(shù)據(jù)源的使用的場(chǎng)景一般有:
- 主從數(shù)據(jù)庫(kù)切換
- 讀寫分離
- 兼容舊庫(kù)
實(shí)現(xiàn)原理
Spring2.x的版本中采用Proxy模式,就是在方案中實(shí)現(xiàn)一個(gè)虛擬的數(shù)據(jù)源,并且用它來封裝數(shù)據(jù)源選擇邏輯,這樣就可以有效地將數(shù)據(jù)源選擇邏輯從Client中分離出來。Client提供選擇所需的上下文,由虛擬的DynamicDataSource根據(jù)Client提供的上下文來實(shí)現(xiàn)數(shù)據(jù)源的選擇。
具體的實(shí)現(xiàn)是虛擬的DynamicDataSource僅需繼承AbstractRoutingDataSource實(shí)現(xiàn)determineCurrentLookupKey(),該方法返回需要使用的DataSource的key值,然后根據(jù)這個(gè)key從resolvedDataSources這個(gè)map里取出對(duì)應(yīng)的DataSource,如果找不到則用默認(rèn)的resolvedDefaultDataSource。
詳細(xì)實(shí)現(xiàn)過程
修改spring的配置文件
配置文件里需要配置多個(gè)數(shù)據(jù)源,改造后主要配置如下:
<bean id="dataSourceTargetA" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" scope="singleton">
<property name="driverClass" value="${jdbc.a.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.a.url}" />
<property name="user" value="${jdbc.a.username}" />
<property name="password" value="${jdbc.a.password}" />
<!--當(dāng)連接池中的連接耗盡的時(shí)候c3p0一次同時(shí)獲取的連接數(shù)。Default: 3 -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property>
<!--初始化時(shí)獲取三個(gè)連接,取值應(yīng)在minPoolSize與maxPoolSize之間。Default: 3 -->
<property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property>
<!--最大空閑時(shí)間,60秒內(nèi)未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->
<property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property>
<!--連接池中保留的最大連接數(shù)。Default: 15 -->
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property>
<property name="minPoolSize" value="${c3p0.minPoolSize}"></property>
<!--兩次連接中間隔時(shí)間,單位毫秒。Default: 1000 -->
<property name="acquireRetryDelay" value="1000"></property>
<!--定義在從數(shù)據(jù)庫(kù)獲取新連接失敗后重復(fù)嘗試的次數(shù)。Default: 30 -->
<property name="acquireRetryAttempts" value="60"></property>
<!--獲取連接失敗將會(huì)引起所有等待連接池來獲取連接的線程拋出異常。但是數(shù)據(jù)源仍有效保留,并在下次調(diào)用getConnection()的時(shí)候繼續(xù)嘗試獲取連接。如果設(shè)為true,那么在嘗試獲取連接失敗后該數(shù)據(jù)源將申明已斷開并永久關(guān)閉。Default:
false -->
<property name="breakAfterAcquireFailure" value="false"></property>
</bean>
<bean id="dataSourceTargetB" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" scope="singleton">
<property name="driverClass" value="${jdbc.b.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.b.url}" />
<property name="user" value="${jdbc.b.username}" />
<property name="password" value="${jdbc.b.password}" />
<!--當(dāng)連接池中的連接耗盡的時(shí)候c3p0一次同時(shí)獲取的連接數(shù)。Default: 3 -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property>
<!--初始化時(shí)獲取三個(gè)連接,取值應(yīng)在minPoolSize與maxPoolSize之間。Default: 3 -->
<property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property>
<!--最大空閑時(shí)間,60秒內(nèi)未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->
<property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property>
<!--連接池中保留的最大連接數(shù)。Default: 15 -->
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property>
<property name="minPoolSize" value="${c3p0.minPoolSize}"></property>
<!--兩次連接中間隔時(shí)間,單位毫秒。Default: 1000 -->
<property name="acquireRetryDelay" value="1000"></property>
<!--定義在從數(shù)據(jù)庫(kù)獲取新連接失敗后重復(fù)嘗試的次數(shù)。Default: 30 -->
<property name="acquireRetryAttempts" value="60"></property>
<!--獲取連接失敗將會(huì)引起所有等待連接池來獲取連接的線程拋出異常。但是數(shù)據(jù)源仍有效保留,并在下次調(diào)用getConnection()的時(shí)候繼續(xù)嘗試獲取連接。如果設(shè)為true,那么在嘗試獲取連接失敗后該數(shù)據(jù)源將申明已斷開并永久關(guān)閉。Default:
false -->
<property name="breakAfterAcquireFailure" value="false"></property>
</bean>
<!-- 動(dòng)態(tài)數(shù)據(jù)源 -->
<bean id="dynamicDataSource" class="com.test.util.DynamicDataSource" >
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="dataSourceTargetA" key="dataSourceTargetA"></entry>
<entry value-ref="dataSourceTargetB" key="dataSourceTargetB"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceTargetA" >
</property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource" />
</bean>
<!-- MyBatis ORM operation class -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<property name="mapperLocations">
<list>
<value>classpath*:com/test/**/*Mapper.xml</value>
</list>
</property>
<property name="configLocation" value="classpath:provider-sql-map-config.xml" />
</bean>
添加動(dòng)態(tài)數(shù)據(jù)源管理類
DynamicDataSource類繼承AbstractRoutingDataSource,實(shí)現(xiàn)determineCurrentLookupKey()方法。
package com.test.util;
import com.test.util.CustomerContextHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 動(dòng)態(tài)數(shù)據(jù)源管理類
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}
數(shù)據(jù)源切換類
CustomerContextHolder類可以實(shí)現(xiàn)數(shù)據(jù)源A和B的切換,數(shù)據(jù)源標(biāo)識(shí)保存在線程變量中,避免多線程操作數(shù)據(jù)源時(shí)互相干擾
package com.test.util;
/**
* 數(shù)據(jù)源切換類
*
*/
public class CustomerContextHolder {
public static final String DATA_SOURCE_DEFAULT = "dataSourceTargetA";
public static final String DATA_SOURCE_B = "dataSourceTargetB";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
return contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
使用多數(shù)據(jù)源代碼
下面是Controller層代碼,需要查詢B數(shù)據(jù)源,查詢完成后切換為默認(rèn)數(shù)據(jù)源A,具體代碼如下:
/**
* 訂單列表查詢,查詢B數(shù)據(jù)源
*
* @param request
* @return
*/
@RequestMapping(value = "/list")
public String list(HttpServletRequest request, Integer cId) {
//設(shè)置數(shù)據(jù)源B
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
List<Order> orderList = salaryBillService.getSalaryOrderByOrgId(cId);
request.setAttribute("orderList", orderList);
//切換回默認(rèn)數(shù)據(jù)源A
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_DEFAULT);
return "/jsp/order";
}
上述四步操作完成后即可實(shí)現(xiàn)SpringMVC+Mybatis配置多個(gè)數(shù)據(jù)源并切換,有問題歡迎留言溝通哦!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?@Conditional注解示例詳細(xì)講解
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件給容器注冊(cè)bean,這篇文章主要介紹了Spring?@Conditional注解示例詳細(xì)講解,需要的朋友可以參考下2022-11-11
Java利用ElasticSearch實(shí)現(xiàn)自動(dòng)補(bǔ)全功能
這篇文章主要為大家詳細(xì)介紹了Java如何利用ElasticSearch實(shí)現(xiàn)跟谷歌和百度類似的下拉補(bǔ)全提示功能,文中的示例代碼講解詳細(xì),需要的可以參考一下2023-08-08
Java項(xiàng)目之java+springboot+ssm實(shí)現(xiàn)理財(cái)管理系統(tǒng)設(shè)計(jì)
這篇文章主要介紹了Java項(xiàng)目java+springboot+ssm實(shí)現(xiàn)理財(cái)管理系統(tǒng)設(shè)計(jì),使用了當(dāng)前較為流行的spring boot,spring,spring mvc,mybatis,shiro框架分頁(yè)處理使用了pagehelper進(jìn)行操作,需要的朋友可以參考一下2022-03-03
Java實(shí)現(xiàn)定時(shí)器的4種方法超全總結(jié)
對(duì)于一些特殊的代碼是需要定時(shí)執(zhí)行的,下面來看看定時(shí)器該如何編寫吧,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)定時(shí)器的4種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
Springboot?接口需要接收參數(shù)類型是數(shù)組問題
這篇文章主要介紹了Springboot?接口需要接收參數(shù)類型是數(shù)組問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
java實(shí)現(xiàn)監(jiān)控rtsp流轉(zhuǎn)flv方法實(shí)例(前端播放,前后端代碼都有)
這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)監(jiān)控rtsp流轉(zhuǎn)flv的相關(guān)資料,文中介紹的是前端播放,前后端代碼都有,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
Java的微信開發(fā)中使用XML格式和JSON格式數(shù)據(jù)的示例

