中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

使用spring怎么實現動態切換

發布時間:2021-05-27 17:21:45 來源:億速云 閱讀:296 作者:Leah 欄目:編程語言

本篇文章為大家展示了使用spring怎么實現動態切換,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

使用spring怎么實現動態切換

使用spring怎么實現動態切換

targetDataSources 就是我們的多個數據源,在初始化的時候會調用afterPropertiesSet(),去解析我們的數據源 然后 put 到 resolvedDataSources

使用spring怎么實現動態切換

實現了 DataSource 的 getConnection(); 我們看看 determineTargetDataSource(); 做了什么

使用spring怎么實現動態切換

通過下面的 determineCurrentLookupKey();(這個方法需要我們實現) 返回一個key,然后從 resolvedDataSources (其實也就是 targetDataSources) 中 get 一個數據源,實現了每次調用 getConnection(); 打開連接 切換數據源,如果想動態添加的話 只需要重新 set targetDataSources 再調用 afterPropertiesSet() 即可

Talk is cheap. Show me the code

我使用的springboot版本為 1.5.x,下面是核心代碼

完整代碼:https://gitee.com/yintianwen7/spring-dynamic-datasource (本地下載)

/**
 * 多數據源配置
 * 
 * @author Taven
 *
 */
@Configuration
@MapperScan("com.gitee.taven.mapper")
public class DataSourceConfigurer {

 /**
  * DataSource 自動配置并注冊
  *
  * @return data source
  */
 @Bean("db0")
 @Primary
 @ConfigurationProperties(prefix = "datasource.db0")
 public DataSource dataSource0() {
  return DruidDataSourceBuilder.create().build();
 }

 /**
  * DataSource 自動配置并注冊
  *
  * @return data source
  */
 @Bean("db1")
 @ConfigurationProperties(prefix = "datasource.db1")
 public DataSource dataSource1() {
  return DruidDataSourceBuilder.create().build();
 }

 /**
  * 注冊動態數據源
  * 
  * @return
  */
 @Bean("dynamicDataSource")
 public DataSource dynamicDataSource() {
  DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
  Map<Object, Object> dataSourceMap = new HashMap<>();
  dataSourceMap.put("dynamic_db0", dataSource0());
  dataSourceMap.put("dynamic_db1", dataSource1());
  dynamicRoutingDataSource.setDefaultTargetDataSource(dataSource0());// 設置默認數據源
  dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
  return dynamicRoutingDataSource;
 }

 /**
  * Sql session factory bean.
  * Here to config datasource for SqlSessionFactory
  * <p>
  * You need to add @{@code @ConfigurationProperties(prefix = "mybatis")}, if you are using *.xml file,
  * the {@code 'mybatis.type-aliases-package'} and {@code 'mybatis.mapper-locations'} should be set in
  * {@code 'application.properties'} file, or there will appear invalid bond statement exception
  *
  * @return the sql session factory bean
  */
 @Bean
 @ConfigurationProperties(prefix = "mybatis")
 public SqlSessionFactoryBean sqlSessionFactoryBean() {
  SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
  // 必須將動態數據源添加到 sqlSessionFactoryBean
  sqlSessionFactoryBean.setDataSource(dynamicDataSource());
  return sqlSessionFactoryBean;
 }

 /**
  * 事務管理器
  *
  * @return the platform transaction manager
  */
 @Bean
 public PlatformTransactionManager transactionManager() {
  return new DataSourceTransactionManager(dynamicDataSource());
 }
}

通過 ThreadLocal 獲取線程安全的數據源 key

package com.gitee.taven.config;

public class DynamicDataSourceContextHolder {

 private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>() {
  @Override
  protected String initialValue() {
   return "dynamic_db0";
  }
 };

 /**
  * To switch DataSource
  *
  * @param key the key
  */
 public static void setDataSourceKey(String key) {
  contextHolder.set(key);
 }

 /**
  * Get current DataSource
  *
  * @return data source key
  */
 public static String getDataSourceKey() {
  return contextHolder.get();
 }

 /**
  * To set DataSource as default
  */
 public static void clearDataSourceKey() {
  contextHolder.remove();
 }
}

動態 添加、切換數據源

/**
 * 動態數據源
 * 
 * @author Taven
 *
 */
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {

 private final Logger logger = LoggerFactory.getLogger(getClass());

 private static Map<Object, Object> targetDataSources = new HashMap<>();
 
 /**
  * 設置當前數據源
  *
  * @return
  */
 @Override
 protected Object determineCurrentLookupKey() {
  logger.info("Current DataSource is [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
  return DynamicDataSourceContextHolder.getDataSourceKey();
 }
 
 @Override
 public void setTargetDataSources(Map<Object, Object> targetDataSources) {
  super.setTargetDataSources(targetDataSources);
  DynamicRoutingDataSource.targetDataSources = targetDataSources;
 }
 
 /**
  * 是否存在當前key的 DataSource
  * 
  * @param key
  * @return 存在返回 true, 不存在返回 false
  */
 public static boolean isExistDataSource(String key) {
  return targetDataSources.containsKey(key);
 }
 
 /**
  * 動態增加數據源
  * 
  * @param map 數據源屬性
  * @return
  */
 public synchronized boolean addDataSource(Map<String, String> map) {
  try {
   Connection connection = null;
   // 排除連接不上的錯誤
   try { 
    Class.forName(map.get(DruidDataSourceFactory.PROP_DRIVERCLASSNAME));
    connection = DriverManager.getConnection(
      map.get(DruidDataSourceFactory.PROP_URL), 
      map.get(DruidDataSourceFactory.PROP_USERNAME),
      map.get(DruidDataSourceFactory.PROP_PASSWORD));
    System.out.println(connection.isClosed());
   } catch (Exception e) {
    return false;
   } finally {
    if (connection != null && !connection.isClosed()) 
     connection.close();
   }
   String database = map.get("database");//獲取要添加的數據庫名
   if (StringUtils.isBlank(database)) return false;
   if (DynamicRoutingDataSource.isExistDataSource(database)) return true; 
   DruidDataSource druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(map);
   druidDataSource.init();
   Map<Object, Object> targetMap = DynamicRoutingDataSource.targetDataSources;
   targetMap.put(database, druidDataSource);
   // 當前 targetDataSources 與 父類 targetDataSources 為同一對象 所以不需要set
//   this.setTargetDataSources(targetMap);
   this.afterPropertiesSet();
   logger.info("dataSource {} has been added", database);
  } catch (Exception e) {
   logger.error(e.getMessage());
   return false;
  }
  return true;
 } 
}

上述內容就是使用spring怎么實現動態切換,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

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

AI

海盐县| 全椒县| 六安市| 枣阳市| 陕西省| 永寿县| 东至县| 临猗县| 曲靖市| 溧阳市| 久治县| 黑龙江省| 家居| 渑池县| 巴南区| 左云县| 阳信县| 茶陵县| 枝江市| 邹城市| 元朗区| 正蓝旗| 建昌县| 绍兴市| 阳曲县| 太谷县| 卓尼县| 双江| 富宁县| 防城港市| 罗田县| 西乌珠穆沁旗| 安庆市| 洛川县| 蓬溪县| 福清市| 呼图壁县| 富民县| 阿城市| 宁乡县| 秦安县|