一個Web項目中實現多個數據庫存儲數據並相互切換

最近公司一個項目需要連接多個數據庫(A和B)操作,根據不同的業務模塊查詢不同的數據庫,因此需要改造下之前的spring-mybatis.xml配置文件以及jdbc.properties配置文件,項目後臺用的是SpringMVC+Mybatis+MySQL架構,折騰了一兩天算是搞定了,在這裏記錄過改造過程。

使用場景

多數據源的使用的場景一般有:

  1. 主從數據庫切換
  2. 讀寫分離
  3. 兼容舊庫

實現原理

    Spring2.x的版本中採用Proxy模式,就是在方案中實現一個虛擬的數據源,並且用它來封裝數據源選擇邏輯,這樣就可以有效地將數據源選擇邏輯從Client中分離出來。Client提供選擇所需的上下文,由虛擬的DynamicDataSource根據Client提供的上下文來實現數據源的選擇。

具體的實現是虛擬的DynamicDataSource僅需繼承AbstractRoutingDataSource實現determineCurrentLookupKey(),該方法返回需要使用的DataSource的key值,然後根據這個key從resolvedDataSources這個map裏取出對應的DataSource,如果找不到則用默認的resolvedDefaultDataSource。

詳細實現過程

  1:修改jdbc.properties的配置文件 

#A 數據源A庫
  jdbc.a.driverClassName=com.mysql.jdbc.Driver
  jdbc.a.url=jdbc:mysql://localhost:3306/exam_zhaosq?useUnicode=true&characterEncoding=utf-8
  jdbc.a.username=root
  jdbc.a.password=root

  #B  數據源B庫
  jdbc.b.driverClassName=com.mysql.jdbc.Driver
  jdbc.b.url=jdbc:mysql://localhost:3306/myshop?useUnicode=true&characterEncoding=utf-8
  jdbc.b.username=root
  jdbc.b.password=root

  2:修改spring-mybatis.xml的配置文件 配置文件裏需要配置多個數據源,改造後主要配置如

<!-- 引入jdbc.properties文件 -->
  <context:property-placeholder location="classpath:jdbc.properties" />
<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}" />
    </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}" />
    </bean>
    <!-- 動態數據源 -->
    <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>

 2.添加動態數據源管理類

 DynamicDataSource類繼承AbstractRoutingDataSource,實現determineCurrentLookupKey()方法。

package com.test.util;
import com.test.util.CustomerContextHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * 動態數據源管理類
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
   @Override
   protected Object determineCurrentLookupKey() {
    return CustomerContextHolder.getCustomerType();
  }
}

3. 數據源切換類

CustomerContextHolder類可以實現數據源A和B的切換,數據源標識保存在線程變量中,避免多線程操作數據源時互相干擾。

package com.test.util;
/**
 * 數據源切換類
 *
 */
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();
      }
}

4. 使用多數據源代碼

下面是Controller層代碼,需要查詢B數據源,查詢完成後切換爲默認數據源A,具體代碼如下:

/**
     * 訂單列表查詢,查詢B數據源
     *
     * @param request
     * @return
     */
@Controller
@RequestMapping(value="/customer")
public class CustomerController
{
      @RequestMapping(value = "/list")
      public String list(HttpServletRequest request, Integer cId) {
            //設置數據源B
            CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
            List<Order> orderList = orderService.getListByCid(cId);
            request.setAttribute("orderList", orderList);
            //切換回默認數據源A
            CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_DEFAULT);
            return "/jsp/order";
    }

   當進入customer方法的時候,會先從數據庫B中的表進行查詢數據,查詢完成後,會切換到默認的數據庫A,然後再從數據庫A中的表查詢數據,這樣就達到了在一個Web項目中,根據不用的模塊和業務需求,實現多個數據庫存儲數據和它們之間的切換了。

上述四步操作完成後即可實現SpringMVC+Mybatis配置多個數據源(庫)並切換,有問題歡迎留言指教!

 好文轉載學習自:https://www.cnblogs.com/haha12/p/10613549.html

 好文轉載學習自:https://www.cnblogs.com/zhaosq/p/10616244.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章