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

溫馨提示×

溫馨提示×

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

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

使用mybatis如何實現動態切換多數據源

發布時間:2020-11-23 15:30:57 來源:億速云 閱讀:164 作者:Leah 欄目:開發技術

使用mybatis如何實現動態切換多數據源?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

具體結構如下:

使用mybatis如何實現動態切換多數據源

在搭建過程集成mybatis的時候,考慮到單一數據源無法滿足實際業務需要,故結合c#的開發經驗,進行多數據源動態集成。

mybatis的多數據源可以采用兩種方式進行,第一種是分包方式實現,這種方式靈活性不高,而且較為繁瑣,故不做過多介紹。

另一種方式是采用AOP的思想,進行注解動態切換,參考網上教程,核心思想是依靠 繼承AbstractRoutingDataSource,重寫determineCurrentLookupKey()方法,在該方法中使用DatabaseContextHolder獲取當前線程的dataSource。

但是網上方法大都是首先定義好各個datasource,比如有三個數據源,就需要實現定義好三個datasource,筆者感覺這種方法,在我目前這套框架中不夠靈活,因為筆者采用的是微服務框架,考慮到各個服務都有可能使用不同的數據源,而多數據源動態切換是放在公共方法中實現的,如果每有新的數據源就要定義一個,對代碼的侵入性太高,在c#中,選擇數據源很容易,根據連接名稱就可以切換過去,如下所示:

<connectionStrings>
<add name="test1" connectionString="server=127.0.0.1;user id=root;password=123456;database=db1;charset=utf8" providerName="MySql.Data.MySqlClient" />
<add name="test2" connectionString="server=127.0.0.1;user id=root;password=123456;database=db2;charset=utf8" providerName="MySql.Data.MySqlClient" />
<add name="test3" connectionString="server=127.0.0.1;user id=root;password=123456;database=db3;charset=utf8" providerName="MySql.Data.MySqlClient" />
<connectionStrings>

能不能像c#這樣根據連接名稱就自動選擇呢,筆者的連接配置如下所示:

spring:
 application:
 name: csg-auth
 datasource:
 kbase:
  - driverClassName: com.kbase.jdbc.Driver
  jdbcUrl: jdbc:kbase://127.0.0.1
  username: DBOWN
  password:
 jdbc:
  - driverClassName: com.mysql.cj.jdbc.Driver
  jdbcUrl: jdbc:mysql://localhost:3306/nacos&#63;serverTimezone=GMT%2B8&useUnicode=false&characterEncoding=utf8&useSSL=false
  username: root
  password: 123456
  connName: nacos
  - driverClassName: com.mysql.cj.jdbc.Driver
  jdbcUrl: jdbc:mysql://localhost:3306/tpi&#63;serverTimezone=GMT%2B8&useUnicode=false&characterEncoding=utf8&useSSL=false
  username: root
  password: 123456
  connName: tpi

其中kbase不用理會,是我們公司自己的數據庫,jdbc是維護的連接集合,其中connName就是我們自定義的連接名稱,
根據connName就可以自動切換到對應數據源。

筆者實現代碼如下:

使用mybatis如何實現動態切換多數據源

第一步

首先,編寫DynamicDataSource類集成AbstractRoutingDataSource,重寫determineCurrentLookupKey方法,該方法主要作用是選擇數據源的key
代碼如下:

/**
 * 動態數據源
 * */
public class DynamicDataSource extends AbstractRoutingDataSource {
 @Override
 protected Object determineCurrentLookupKey() {
  return DataSourceHolder.getDataSource();
 }
}

第二步

第二部編寫DataSourceHolder類,提供設置、獲取、情況數據源的方法,如下所示:

public class DataSourceHolder {
 /**
  * 線程本地環境
  */
 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();

 /**
  * 設置數據源
  */
 public static void setDataSources(String connName) {
  dataSources.set(connName);
 }

 /**
  * 獲取數據源
  */
 public static String getDataSource() {
  return dataSources.get();
 }

 /**
  * 清楚數據源
  */
 public static void clearDataSource() {
  dataSources.remove();
 }
}

第三步

第三步,編寫DataSourceConfig類,該類主要作用是讀取配置文件中的數據源連接集合,以及維護項目數據源的Bean對象,
代碼如下:

@Component
@ConfigurationProperties("spring.datasource")
public class DataSourceConfig {
 private List<DataSourceModel> jdbc;

 public Map<Object, Object> getDataSourceMap(){
  Map<Object, Object>map=new HashMap<>();
  if (jdbc!=null&&jdbc.size()>0){
   for (int i = 0; i < jdbc.size() ; i++) {
    DataSourceBuilder dataSourceBuilder=DataSourceBuilder.create();
    dataSourceBuilder.driverClassName(jdbc.get(i).getDriverClassName());
    dataSourceBuilder.password(jdbc.get(i).getPassword());
    dataSourceBuilder.username(jdbc.get(i).getUsername());
    dataSourceBuilder.url(jdbc.get(i).getJdbcUrl());
    map.put(jdbc.get(i).getConnName(),dataSourceBuilder.build());
   }
  }
  return map;
 }

 @Bean
 public DataSource csgDataSource(){
  DynamicDataSource dynamicDataSource=new DynamicDataSource();
  Map<Object,Object>dataSourceMap=getDataSourceMap();
  dynamicDataSource.setTargetDataSources(dataSourceMap);
   Object object= dataSourceMap.values().toArray()[0];
  dynamicDataSource.setDefaultTargetDataSource(object);
  return dynamicDataSource;
 }

 public void setJdbc(List<DataSourceModel> jdbc) {
  this.jdbc = jdbc;
 }

 public List<DataSourceModel> getJdbc(){
  return this.jdbc;
 }
}

其中,getDataSourceMap()方法,作用是根據配置的連接集合,生成AbstractRoutingDataSource所需要的resolvedDataSources。

而csgDataSource()方法,添加了@Bean注解,作用是讓mybatis的SqlSessionFactory,能夠使用咱們維護的數據源。

第四部

編寫MyBatisConfig類,該類主要作用是 配置好mybatis的數據源。

@Configuration
public class MyBatisConfig {

 @Autowired
 private DataSource csgDataSource;

 @Bean
 public SqlSessionFactory sqlSessionFactory() throws Exception {
  SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
  sqlSessionFactoryBean.setDataSource(csgDataSource);
  sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
    .getResources("classpath:mapper/**/*.xml"));
  return sqlSessionFactoryBean.getObject();
 }

 @Bean
 public PlatformTransactionManager platformTransactionManager(){
  return new DataSourceTransactionManager(csgDataSource);
 }
}

可以看到,這里選擇的是我們定義好的csgDataSource,其作用也是如此。

第五步

編寫TargetDataSource注解

/**
 * 注解標簽
 * 作用于 方法、接口、類、枚舉、注解
 * */

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface TargetDataSource {
 String connName();
}

其中connName,就是我們需要使用的數據源

第六步

編寫DataSourceExchange,改類為切面,作用于TargetDataSource注解,故使用TargetDataSource注解的時候,
會根據connName自動選擇數據源。

@Aspect
@Component
public class DataSourceExchange {

 @Before("@annotation(TargetDataSource)")
 public void before(JoinPoint joinPoint){
  MethodSignature sign = (MethodSignature) joinPoint.getSignature();
  Method method = sign.getMethod();
  boolean isMethodAop= method.isAnnotationPresent(TargetDataSource.class);
  if (isMethodAop){
   TargetDataSource datasource = method.getAnnotation(TargetDataSource.class);
   DataSourceHolder.setDataSources(datasource.connName());
  }else {
   if (joinPoint.getTarget().getClass().isAnnotationPresent(TargetDataSource.class)){
    TargetDataSource datasource = joinPoint.getTarget().getClass().getAnnotation(TargetDataSource.class);
    DataSourceHolder.setDataSources(datasource.connName());
   }
  }
 }

 @After("@annotation(TargetDataSource)")
 public void after(){
  DataSourceHolder.clearDataSource();
 }
}

改切面作用于方法運行前后,負責選擇、取消數據源。

第七部

開始驗證,使用方法如下:

@Service
public class UserServiceImpl implements UserService {
 @Autowired
 private UserMapper userMapper;

 @Override
 @TargetDataSource(connName = "nacos")
 public List<UserEntity> getList() {
  List<UserEntity> list= userMapper.selectUserList();
  return list;
 }
}

在service中,在需要進行數據庫操作的方法上,添加TargetDataSource注解,即可自動切換到所需要的數據源。
至此,mybatis就可以動態切換數據源了。

看完上述內容,你們掌握使用mybatis如何實現動態切換多數據源的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

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

AI

威海市| 蕉岭县| 枞阳县| 绥棱县| 五峰| 伊川县| 河北区| 绩溪县| 镇平县| 武宣县| 云阳县| 荃湾区| 柯坪县| 桐梓县| 雷州市| 巴中市| 临沂市| 甘南县| 辽中县| 富蕴县| 岳池县| 凤城市| 开阳县| 嘉兴市| 五家渠市| 贞丰县| 尤溪县| 时尚| 合肥市| 阳春市| 马龙县| 石河子市| 汾西县| 西峡县| 邛崃市| 兴海县| 奎屯市| 花莲市| 麻栗坡县| 达州市| 岳池县|