国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Spring+Mybatis動態(tài)切換數(shù)據(jù)源的方法

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

2021-03-27 14:09pengyuzhu Java教程

這篇文章主要為大家詳細介紹了Spring+Mybatis動態(tài)切換數(shù)據(jù)源的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下

功能需求是公司要做一個大的運營平臺:

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

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!-- op datasource -->
  <bean id="opdatasource" class="com.alibaba.druid.pool.druiddatasource"
    init-method="init" destroy-method="close">
    <property name="url" value="${db.master.url}" />
    <property name="username" value="${db.master.user}" />
    <property name="password" value="${db.master.password}" />
    <property name="driverclassname" value="${db.master.driver}" />
    <property name="initialsize" value="5" />
    <property name="maxactive" value="100" />
    <property name="minidle" value="10" />
    <property name="maxwait" value="60000" />
    <property name="validationquery" value="select 'x'" />
    <property name="testonborrow" value="false" />
    <property name="testonreturn" value="false" />
    <property name="testwhileidle" value="true" />
    <property name="timebetweenevictionrunsmillis" value="600000" />
    <property name="minevictableidletimemillis" value="300000" />
    <property name="removeabandoned" value="true" />
    <property name="removeabandonedtimeout" value="1800" />
    <property name="logabandoned" value="true" />
    <!-- 配置監(jiān)控統(tǒng)計攔截的filters -->
    <property name="filters" value="config,mergestat,wall,log4j2" />
    <property name="connectionproperties" value="config.decrypt=true" />
  </bean>
 
  <!-- servera datasource -->
  <bean id="serveradatasource" class="com.alibaba.druid.pool.druiddatasource"
    init-method="init" destroy-method="close">
    <property name="url" value="${db.servera.master.url}" />
    <property name="username" value="${db.servera.master.user}" />
    <property name="password" value="${db.servera.master.password}" />
    <property name="driverclassname" value="${db.servera.master.driver}" />
    <property name="initialsize" value="5" />
    <property name="maxactive" value="100" />
    <property name="minidle" value="10" />
    <property name="maxwait" value="60000" />
    <property name="validationquery" value="select 'x'" />
    <property name="testonborrow" value="false" />
    <property name="testonreturn" value="false" />
    <property name="testwhileidle" value="true" />
    <property name="timebetweenevictionrunsmillis" value="600000" />
    <property name="minevictableidletimemillis" value="300000" />
    <property name="removeabandoned" value="true" />
    <property name="removeabandonedtimeout" value="1800" />
    <property name="logabandoned" value="true" />
    <!-- 配置監(jiān)控統(tǒng)計攔截的filters -->
    <property name="filters" value="config,mergestat,wall,log4j2" />
    <property name="connectionproperties" value="config.decrypt=true" />
  </bean>
 
  <!-- serverb datasource -->
  <bean id="serverbdatasource" class="com.alibaba.druid.pool.druiddatasource"
    init-method="init" destroy-method="close">
    <property name="url" value="${db.serverb.master.url}" />
    <property name="username" value="${db.serverb.master.user}" />
    <property name="password" value="${db.serverb.master.password}" />
    <property name="driverclassname" value="${db.serverb.master.driver}" />
    <property name="initialsize" value="5" />
    <property name="maxactive" value="100" />
    <property name="minidle" value="10" />
    <property name="maxwait" value="60000" />
    <property name="validationquery" value="select 'x'" />
    <property name="testonborrow" value="false" />
    <property name="testonreturn" value="false" />
    <property name="testwhileidle" value="true" />
    <property name="timebetweenevictionrunsmillis" value="600000" />
    <property name="minevictableidletimemillis" value="300000" />
    <property name="removeabandoned" value="true" />
    <property name="removeabandonedtimeout" value="1800" />
    <property name="logabandoned" value="true" />
    <!-- 配置監(jiān)控統(tǒng)計攔截的filters -->
    <property name="filters" value="config,mergestat,wall,log4j2" />
    <property name="connectionproperties" value="config.decrypt=true" />
  </bean>

我配置了三個數(shù)據(jù)源:opdatasource(運營平臺本身的數(shù)據(jù)源),serveradatasource,serverbdatasource。

2、配置multipledatasource

multipledatasource相當于以上三個數(shù)據(jù)源的一個代理,真正與spring/mybatis相結(jié)合的時multipledatasource,和單獨配置的datasource使用沒有分別:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!-- spring整合mybatis:配置multipledatasource -->
  <bean id="sqlsessionfactory"
    class="com.baomidou.mybatisplus.spring.mybatissqlsessionfactorybean">
    <property name="datasource" ref="multipledatasource" />
    <!-- 自動掃描mapping.xml文件 -->
    <property name="mapperlocations">
      <list>
        <value>classpath*:/sqlmapperxml/*.xml</value>
        <value>classpath*:/sqlmapperxml/*/*.xml</value>
      </list>
    </property>
    <property name="configlocation" value="classpath:xml/mybatis-config.xml"></property>
    <property name="typealiasespackage" value="com.xxx.platform.model" />
    <property name="globalconfig" ref="globalconfig" />
    <property name="plugins">
      <array>
        <!-- 分頁插件配置 -->
        <bean id="paginationinterceptor"
          class="com.baomidou.mybatisplus.plugins.paginationinterceptor">
          <property name="dialecttype" value="mysql" />
          <property name="optimizetype" value="alidruid" />
        </bean>
      </array>
    </property>
  </bean>
  
  <!-- mybatis 動態(tài)實現(xiàn) -->
  <bean id="mapperscannerconfigurer" class="org.mybatis.spring.mapper.mapperscannerconfigurer">
    <!-- 對dao 接口動態(tài)實現(xiàn),需要知道接口在哪 -->
    <property name="basepackage" value="com.xxx.platform.mapper" />
    <property name="sqlsessionfactorybeanname" value="sqlsessionfactory"></property>
  </bean> 
  <!-- mp 全局配置 -->
  <bean id="globalconfig" class="com.baomidou.mybatisplus.entity.globalconfiguration">
    <property name="idtype" value="0" />
    <property name="dbcolumnunderline" value="true" />
  </bean>
 
 
  <!-- 事務(wù)管理配置multipledatasource -->
  <bean id="transactionmanager"
    class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
    <property name="datasource" ref="multipledatasource"></property>
  </bean>

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

?
1
2
3
4
5
6
7
8
9
10
<bean id="multipledatasource" class="com.xxxx.platform.commons.db.multipledatasource">
    <property name="defaulttargetdatasource" ref="opdatasource" />
    <property name="targetdatasources">
      <map>
        <entry key="opdatasource" value-ref="opdatasource" />
        <entry key="serveradatasource" value-ref="serveradatasource" />
        <entry key="serverbdatasource" value-ref="serverbdatasource" />
      </map>
    </property>
  </bean>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource;
 
/**
 *
 * @classname: multipledatasource
 * @description: 配置多個數(shù)據(jù)源<br>
 * @author: yuzhu.peng
 * @date: 2018年1月12日 下午4:37:25
 */
public class multipledatasource extends abstractroutingdatasource {
  
  private static final threadlocal<string> datasourcekey = new inheritablethreadlocal<string>();
  
  public static void setdatasourcekey(string datasource) {
    datasourcekey.set(datasource);
  }
  
  @override
  protected object determinecurrentlookupkey() {
    return datasourcekey.get();
  }
  
  public static void removedatasourcekey() {
    datasourcekey.remove();
  }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*獲取連接*/
  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實現(xiàn)的接口*/
  protected abstract object determinecurrentlookupkey();

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

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

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

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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ù)實現(xiàn)類請求之前進行數(shù)據(jù)源切換 特別注意,由于用到了多數(shù)據(jù)源,mapper的調(diào)用最好只在*serviceimpl,不然調(diào)用到非默認數(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ù)源,否則默認為后臺的數(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);
    }
  }
  
  /**
   * 當操作完成時,釋放當前的數(shù)據(jù)源 如果不釋放,頻繁點擊時會發(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í)行完后,釋放當前的數(shù)據(jù)源。注意我用到了spring的 @order,注解,接下來會講到,當定義多個aop的時候,order是很有用的。

其他:

一開始項目中并沒有引入事務(wù),所以一切都ok,每次都能訪問到正確的數(shù)據(jù)源,當加入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)容,希望對大家的學習有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://www.cnblogs.com/zackzhuzi/archive/2018/01/26/8359940.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 伊人干 | 欧美影 | 2019中文字幕视频 | 国产精品高潮呻吟久久av野狼 | 香蕉久久久久久 | 淫片免费观看 | 99久久久无码国产精品 | 日韩精品成人 | 国产欧美日韩一区二区三区 | 国产一区二区三区在线 | 亚洲电影免费 | 久久精品亚洲 | 欧美成人一区二区 | 成人午夜 | 欧美日韩一区二区视频在线观看 | 艹逼网 | 亚洲区在线 | 精品国产乱码久久久久久影片 | 久久精品一区二区三区中文字幕 | 国产成人免费在线 | 黄色av免费 | 曰批免费视频播放免费 | 视频一区二区三区中文字幕 | 香蕉视频禁止18 | 成人av观看 | 国产午夜精品一区二区三区视频 | 久久精品亚洲成在人线av网址 | 中文字幕二区 | 欧美日韩国产精品一区二区 | 日韩在线一| 欧美大片免费高清观看 | 欧美综合成人网 | 国产精品a级 | 欧美人交a欧美精品 | 久草热8精品视频在线观看 欧美黄色小视频 | 日本少妇bbbb爽爽bbb美 | 激情久久av一区av二区av三区 | 亚洲在线视频 | 在线观看中文字幕亚洲 | 亚洲欧美在线一区 | 久久精品国产亚洲 |