真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Spring+Mybatis動態(tài)切換數(shù)據(jù)源的方法

功能需求是公司要做一個大的運(yùn)營平臺:

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、城中ssl等。為超過千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的城中網(wǎng)站制作公司

1、運(yùn)營平臺有自身的數(shù)據(jù)庫,維護(hù)用戶、角色、菜單、部分以及權(quán)限等基本功能。

2、運(yùn)營平臺還需要提供其他不同服務(wù)(服務(wù)A,服務(wù)B)的后臺運(yùn)營,服務(wù)A、服務(wù)B的數(shù)據(jù)庫是獨(dú)立的。

所以,運(yùn)營平臺至少要連三個庫:運(yùn)營庫,A庫,B庫,并且希望達(dá)到針對每個功能請求能夠自動切換到對應(yīng)的數(shù)據(jù)源(我最終實(shí)現(xiàn)是針對Service的方法級別進(jìn)行切換的,也可以實(shí)現(xiàn)針對每個DAO層的方法進(jìn)行切換。我們系統(tǒng)的功能是相互之間比較獨(dú)立的)。

第一步:配置多數(shù)據(jù)源

1、定義數(shù)據(jù)源:

我采用的數(shù)據(jù)源是阿里的DruidDataSource(用DBCP也行,這個隨便)。配置如下:


  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  

  
  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  

  
  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
  

我配置了三個數(shù)據(jù)源:oPDataSource(運(yùn)營平臺本身的數(shù)據(jù)源),serverADataSource,serverBDataSource。

2、配置multipleDataSource

multipleDataSource相當(dāng)于以上三個數(shù)據(jù)源的一個代理,真正與Spring/Mybatis相結(jié)合的時multipleDataSource,和單獨(dú)配置的DataSource使用沒有分別:


  
    
    
    
      
        classpath*:/sqlMapperXml/*.xml
        classpath*:/sqlMapperXml/*/*.xml
      
    
    
    
    
    
      
        
        
          
          
        
      
    
  
  
  
  
    
    
    
    
  
  
    
    
  


  
  
    
  

了解了multipleDataSource所處的位置之后,接下來重點(diǎn)看下multipleDataSource怎么實(shí)現(xiàn),配置文件如下:


    
    
      
        
        
        
      
    
  

實(shí)現(xiàn)的Java代碼如下,不需要過多的解釋,很一目了然:

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 
 * @ClassName: MultipleDataSource
 * @Description: 配置多個數(shù)據(jù)源
* @author: yuzhu.peng * @date: 2018年1月12日 下午4:37:25 */ public class MultipleDataSource extends AbstractRoutingDataSource { private static final ThreadLocal dataSourceKey = new InheritableThreadLocal(); public static void setDataSourceKey(String dataSource) { dataSourceKey.set(dataSource); } @Override protected Object determineCurrentLookupKey() { return dataSourceKey.get(); } public static void removeDataSourceKey() { dataSourceKey.remove(); } }

繼承自spring的AbstractRoutingDataSource,實(shí)現(xiàn)抽象方法determineCurrentLookupKey,這個方法會在每次獲得數(shù)據(jù)庫連接Connection的時候之前,決定本次連接的數(shù)據(jù)源Datasource,可以看下Spring的代碼就很清晰了:

/*獲取連接*/
  public Connection getConnection()
    throws SQLException {
    return determineTargetDataSource().getConnection();
  }

  protected DataSource determineTargetDataSource() {
    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    /*此處的determineCurrentLookupKey為抽象接口,獲取具體的數(shù)據(jù)源名稱*/
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);
    if ((dataSource == null) && (((this.lenientFallback) || (lookupKey == null)))) {
      dataSource = this.resolvedDefaultDataSource;
    }
    if (dataSource == null) {
      throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    }
    return dataSource;
  }
  /*抽象接口:也即我們的multipleDataSource實(shí)現(xiàn)的接口*/
  protected abstract Object determineCurrentLookupKey();

第二步:每次請求(Service方法級別)動態(tài)切換數(shù)據(jù)源

 實(shí)現(xiàn)思路是利用Spring的AOP思想,攔截每次的Service方法調(diào)用,然后根據(jù)方法的整體路徑名,動態(tài)切換multipleDataSource中的數(shù)據(jù)的key。我們的項(xiàng)目,針對不同服務(wù)也即不同數(shù)據(jù)庫的操作,是彼此之間互相獨(dú)立的,不太建議在同一個service方法中調(diào)用不同的數(shù)據(jù)源,這樣的話需要將動態(tài)判斷是否需要切換的頻次(AOP攔截的頻次)放在DAO級別,也就是SQL級別。另外,還不方便進(jìn)行事務(wù)管理。

我們來看動態(tài)切換數(shù)據(jù)源的AOP實(shí)現(xiàn):

import java.lang.reflect.Proxy;

import org.apache.commons.lang.ClassUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;

/**
 * 數(shù)據(jù)源切換AOP
 * 
 * @author yuzhu.peng
 * @since 2018-01-15
 */
@Aspect
@Order(1)
public class MultipleDataSourceInterceptor {
  /**
   * 攔截器對所有的業(yè)務(wù)實(shí)現(xiàn)類請求之前進(jìn)行數(shù)據(jù)源切換 特別注意,由于用到了多數(shù)據(jù)源,Mapper的調(diào)用最好只在*ServiceImpl,不然調(diào)用到非默認(rèn)數(shù)據(jù)源的表時,會報表不存在的異常
   * 
   * @param joinPoint
   * @throws Throwable
   */
  @Before("execution(* com.xxxx.platform.service..*.*ServiceImpl.*(..))")
  public void setDataSoruce(JoinPoint joinPoint)
    throws Throwable {
    Class<?> clazz = joinPoint.getTarget().getClass();
    String className = clazz.getName();
    if (ClassUtils.isAssignable(clazz, Proxy.class)) {
      className = joinPoint.getSignature().getDeclaringTypeName();
    }
    // 對類名含有serverA的設(shè)置為serverA數(shù)據(jù)源,否則默認(rèn)為后臺的數(shù)據(jù)源
    if (className.contains(".serverA.")) {
      MultipleDataSource.setDataSourceKey(DBConstant.DATA_SOURCE_serverA);
    }
    else if (className.contains(".serverB.")) {
      MultipleDataSource.setDataSourceKey(DBConstant.DATA_SOURCE_serverB);
    }
    else {
      MultipleDataSource.setDataSourceKey(DBConstant.DATA_SOURCE_OP);
    }
  }
  
  /**
   * 當(dāng)操作完成時,釋放當(dāng)前的數(shù)據(jù)源 如果不釋放,頻繁點(diǎn)擊時會發(fā)生數(shù)據(jù)源沖突,本是另一個數(shù)據(jù)源的表,結(jié)果跑到另外一個數(shù)據(jù)源去,報表不存在
   * 
   * @param joinPoint
   * @throws Throwable
   */
  @After("execution(* com.xxxx.service..*.*ServiceImpl.*(..))")
  public void removeDataSoruce(JoinPoint joinPoint)
    throws Throwable {
    MultipleDataSource.removeDataSourceKey();
  }
}

攔截所有的ServiceImpl方法,根據(jù)方法的全限定名去判斷屬于那個數(shù)據(jù)源的功能,然后選擇相應(yīng)的數(shù)據(jù)源,發(fā)放執(zhí)行完后,釋放當(dāng)前的數(shù)據(jù)源。注意我用到了Spring的 @Order,注解,接下來會講到,當(dāng)定義多個AOP的時候,order是很有用的。

其他:

一開始項(xiàng)目中并沒有引入事務(wù),所以一切都OK,每次都能訪問到正確的數(shù)據(jù)源,當(dāng)加入SPring的事務(wù)管理后,不能動態(tài)切換數(shù)據(jù)源了(也好像是事務(wù)沒有生效,反正是二者沒有同時有效),后來發(fā)現(xiàn)原因是AOP的執(zhí)行順序問題,所以用到了上邊提到的SPring的Order:

Spring+Mybatis動態(tài)切換數(shù)據(jù)源的方法

Spring+Mybatis動態(tài)切換數(shù)據(jù)源的方法

 order越小,先被執(zhí)行。至此,既可以動態(tài)切換數(shù)據(jù)源,又可以成功用事務(wù)(在同一個數(shù)據(jù)源)。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。


網(wǎng)頁標(biāo)題:Spring+Mybatis動態(tài)切換數(shù)據(jù)源的方法
文章來源:http://weahome.cn/article/iepcjs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部