亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

詳解基于spring多數據源動態調用及其事務處理

發布時間:2020-09-17 17:24:02 來源:腳本之家 閱讀:173 作者:atheva 欄目:編程語言

需求:

有些時候,我們需要連接多個數據庫,但是,在方法調用前并不知道到底是調用哪個。即同時保持多個數據庫的連接,在方法中根據傳入的參數來確定。

下圖的單數據源的調用和多數據源動態調用的流程,可以看出在Dao層中需要有一個DataSource選擇器,來確定到底是調用哪個數據源。

詳解基于spring多數據源動態調用及其事務處理

實現方式

對Dao層提供一個公共父類,保持有多個數據源的連接(本人是基于iBatis,即保持多個SQLSessionTemplate)

/**

 * Created by hzlizhou on 2017/2/6.

 */

public abstract class MultiDatasourceDao implements IDaoSupport {

 

  private Map<String, SqlSessionTemplate> sqlSessionTemplateMap;

 

  private MultiDataSourceSelector multiDataSourceSelector;

 

  public MultiDatasourceDao(Map<String, SqlSessionTemplate> sqlSessionTemplateMap, MultiDataSourceSelector multiDataSourceSelector) {

    this.sqlSessionTemplateMap = sqlSessionTemplateMap;

    this.multiDataSourceSelector = multiDataSourceSelector;

  }

 

  public Map<String, SqlSessionTemplate> getSqlSessionTemplateMap() {

    return sqlSessionTemplateMap;

  }

 

  public void setSqlSessionTemplateMap(Map<String, SqlSessionTemplate> sqlSessionTemplateMap) {

    this.sqlSessionTemplateMap = sqlSessionTemplateMap;

  }

 

  //子類通過這個方法動態獲取SqlSessionTemplate

  protected SqlSessionTemplate getSqlSessionTemplate() {

    String clusterName = multiDataSourceSelector.getName();

    SqlSessionTemplate result = sqlSessionTemplateMap.get(clusterName);

    Assert.notNull(result);

    return result;

  }

}  

MultiDataSourceSelector是一個借口,根據當前的調用環境,返回不不同的參數,根據這個參數就可以確定使用哪一個SQLSessionTemplate,例如我是把當前環境放入到ThreadLocal中的

public interface MultiDataSourceSelector {

  String getName();

}

public class DubboContextDataSourceSelector implements MultiDataSourceSelector {

 

  private String defaultName;

 

  public DubboContextDataSourceSelector(String defaultName) {

    this.defaultName = defaultName;

  }

 

  @Override

  public String getName() {

    //DubboContextHolder 是一個保持一個ThreadLocal的Map

    String res = DubboContextHolder.getContext().get(DubboContextConstants.CLUSTER_NAME);

    if (res == null) {

      res = getDefaultName();

    }

    return res;

  }

 

  public String getDefaultName() {

    return defaultName;

  }

} 

然后在Dao層的中獲取SQLSessionTemplate的時候就是動態了。

動態事務

其實這個都好辦,然后我們就面臨一個稍微復雜一點的問題,那DataSource是動態的,事務也就必須是動態了的。而且還對原有的代碼沒有侵入(例如Spring中的@Transactional 注解),那實現一個類似@Transactional的方法吧。名字就叫做@DynamicTransactional

@Documented

@Target({METHOD, TYPE})

@Retention(RUNTIME)

public @interface DynamicTransactional {

 

  Propagation propagation() default Propagation.REQUIRED;

 

  Class<? extends Throwable>[] rollbackFor() default {};

} 

基本思想是在通過AOP切面攔截@DynamicTransactional注解,調用,然后自己編程實現事務

詳解基于spring多數據源動態調用及其事務處理

切面內的核心方法是

private Object invokeWithinTransaction(final ProceedingJoinPoint pjp, final DynamicTransactional dynamicTransaction) {

 

  //創建TransactionTemplate

  final PlatformTransactionManager tran = multiTransactionManagerHolder.getTransactionManager();

  TransactionTemplate transactionTemplate = new TransactionTemplate();

  transactionTemplate.setPropagationBehavior(dynamicTransaction.propagation().value());

  transactionTemplate.setTransactionManager(tran);

 

  //在事務中執行

  return transactionTemplate.execute(new TransactionCallback<Object>() {

    @Override

    public Object doInTransaction(TransactionStatus status) {

      Object result = null;

      try {

        result = pjp.proceed();

      } catch (Throwable throwable) {

        Class<? extends Throwable>[] c = dynamicTransaction.rollbackFor();

        for (Class<? extends Throwable> tmp : c) {

          if (tmp.isAssignableFrom(throwable.getClass())) {

            status.setRollbackOnly();

          }

        }

      }

      return result;

    }

  });

} 

其中multiTransactionManagerHolder和上面動態數據源選擇的原理一樣,通過從ThreadLocal中拿去變量,選擇對應的TransactionManager返回

 切面的配置:重點是怎么對指定注解進行切面

<aop:config>

  <aop:aspect id="multiTransactionManagerAspect" ref="multiTransactionManagerAop">

    <aop:around method="invokeWithinTransaction"

               arg-names="dynamicTransaction"

               pointcut="@annotation(dynamicTransaction)"/>

  </aop:aspect>

</aop:config>

當然,這里只是實現了在方法上的@DynamicTransactional使用,如果該注解還要對類使用,對所有函數加一個切點,判斷該切點的類上是否有@DynamicTransactional注解

注意:由于切面的優先級,如果要實現 方法上的注解優先級高于類上的,還需要一點點小的處理

調用時序圖

自己實現基于AbstractRoutingDataSource,把多個DataSource加入到SQLSessionFactory,和之前的方式一樣,通過ThreadLocal來確定使用哪個DataSource。

詳解基于spring多數據源動態調用及其事務處理

關于動態事務,上面是使用切面,自定義標簽,使用TransactionTemplate來實現的,如果想更優雅的話,可以仿照DataSourceTransactionManager寫一個,

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

田阳县| 铁力市| 抚州市| 成安县| 台州市| 奉化市| 枞阳县| 抚顺县| 黔西| 天峨县| 娄底市| 汨罗市| 灵璧县| 秀山| 石阡县| 信阳市| 车致| 象山县| 新乡市| 天门市| 酉阳| 九龙城区| 桓台县| 岐山县| 且末县| 临洮县| 承德县| 保靖县| 淮北市| 舞阳县| 绥中县| 马鞍山市| 香河县| 甘孜县| 宁远县| 滨海县| 石泉县| 南澳县| 南开区| 临泽县| 庆元县|