springboot中mybatis多數據源動態切換實現

在開發中,動態數據源配置還是用的比較多的,比如在多數據源使用方面,又或者是在多個DB之間切換方面。這裡給出一個動態數據源的配置方案,兩個DB均以mysql為例。

多數據源配置引入

mybatis和mysql在springboot中的引入這裡就不在說瞭,不瞭解的可以參見springboot中mysql與mybatis的引入。

數據源配置如下:

datasource:
  master:
    type: com.alibaba.druid.pool.DruidDataSource
    jdbc-url: jdbc:mysql://127.0.0.1:3306/sbac_master?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver
  log:
    type: com.alibaba.druid.pool.DruidDataSource
    jdbc-url: jdbc:mysql://127.0.0.1:3306/sbac_log?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis的配置引入如下:

mybatis:
  config-location: classpath:mybatis-config.xml
  mapper-locations: classpath:com/lazycece/sbac/mysql/data/dao/*/mapper/*.xml

這裡已然使用的是springboot的自動配置功能配置mybatis信息,隻是手動指定瞭數據源的。如下所示,指定瞭master和log兩個數據源,設置master為默認數據源:

@Configuration
public class MultiDataSource {

    public static final String MASTER_DATA_SOURCE = "masterDataSource";
    public static final String LOG_DATA_SOURCE = "logDataSource";

    @Bean(name = MultiDataSource.MASTER_DATA_SOURCE)
    @ConfigurationProperties(prefix = "datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = MultiDataSource.LOG_DATA_SOURCE)
    @ConfigurationProperties(prefix = "datasource.log")
    public DataSource logDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
        Map<Object, Object> dataSourceMap = new HashMap<>(4);
        dataSourceMap.put(MASTER_DATA_SOURCE, masterDataSource());
        dataSourceMap.put(LOG_DATA_SOURCE, logDataSource());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;
    }
}

動態數據源路由實現

引入瞭配置信息之後,便是該說如何實現多數據源切換瞭。我們是通過實現AbstractRoutingDataSource類的determineCurrentLookupKey方法來實現數據源的動態路由,設置ThreadLocal線程保護變量存儲數據源key,確保線程間不受影響。

package com.lazycece.sbac.mysql.multi.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author lazycece
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSource.class);

    private static final ThreadLocal<String> DATA_SOURCE_KEY = new ThreadLocal<>();

    static void changeDataSource(String dataSourceKey) {
        DATA_SOURCE_KEY.set(dataSourceKey);
    }

    static void clearDataSource() {
        DATA_SOURCE_KEY.remove();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        String key = DATA_SOURCE_KEY.get();
        LOGGER.info("current data-source is {}", key);
        return key;
    }
}

隨後,便是用AOP的方式來實現數據源的動態切換,註解和切面定義如下:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DataSource {

    String value();
}

@Component
@Aspect
public class DataSourceConfig {

    @Before("@annotation(dataSource)")
    public void beforeSwitchDataSource(DataSource dataSource) {
        DynamicDataSource.changeDataSource(dataSource.value());
    }

    @After("@annotation(DataSource)")
    public void afterSwitchDataSource() {
        DynamicDataSource.clearDataSource();
    }
}

動態數據源切換使用

動態數據源切換隻需要在業務中使用@DataSource註解來標明需要使用的數據源即可,如下所示(這裡隻貼出關鍵代碼):

@Service
public class DynamicDataSourceServiceImpl implements DynamicDataSourceService {

    @Resource
    private UserDao userDao;
    @Resource
    private SystemLogDao systemLogDao;

    @Override
    @DataSource(value = MultiDataSource.MASTER_DATA_SOURCE)
    public void addUserInfo(User user) {
        userDao.insert(user);
    }

    @Override
    @DataSource(value = MultiDataSource.MASTER_DATA_SOURCE)
    public User getUserInfo(String username) {
        return userDao.findByUsername(username);
    }

    @Override
    @DataSource(value = MultiDataSource.LOG_DATA_SOURCE)
    public void addSystemLog(SystemLog systemLog) {
        systemLogDao.insert(systemLog);
    }

    @Override
    @DataSource(value = MultiDataSource.LOG_DATA_SOURCE)
    public List<SystemLog> getSystemLogInfo(Date beginTime, Date endTime) {
        return systemLogDao.findByCreateTime(beginTime, endTime);
    }
}

案例源碼

案例源碼地址: https://github.com/lazycece/springboot-actual-combat/tree/master/springboot-ac-mysql/springboot-ac-mysql-multi

到此這篇關於springboot中mybatis多數據源動態切換實現的文章就介紹到這瞭,更多相關springboot mybatis多數據源動態切換內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: