springboot中mybatis多数据源动态切换实现

 更新时间:2021年07月23日 10:56:34   作者:lazycece  
在开发中,动态数据源配置还是用的比较多的,比如在多数据源使用方面,又或者是在多个DB之间切换方面。这里给出一个动态数据源的配置方案,感兴趣的可以了解一下

在开发中,动态数据源配置还是用的比较多的,比如在多数据源使用方面,又或者是在多个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多数据源动态切换内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java内部类之成员内部类、局部内部类和匿名内部类用法及说明

    java内部类之成员内部类、局部内部类和匿名内部类用法及说明

    这篇文章主要介绍了java内部类之成员内部类、局部内部类和匿名内部类的用法及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Spring Retry重试框架的使用讲解

    Spring Retry重试框架的使用讲解

    重试的使用场景比较多,比如调用远程服务时,由于网络或者服务端响应慢导致调用超时,此时可以多重试几次。用定时任务也可以实现重试的效果,但比较麻烦,用Spring Retry的话一个注解搞定所有,感兴趣的可以了解一下
    2022-10-10
  • Spark Streaming编程初级实践详解

    Spark Streaming编程初级实践详解

    这篇文章主要为大家介绍了Spark Streaming编程初级实践详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • 详解Spring Bean的配置方式与实例化

    详解Spring Bean的配置方式与实例化

    本文主要带大家一起学习一下Spring Bean的配置方式与实例化,文中的示例代码讲解详细,对我们学习Spring有一定的帮助,需要的可以参考一下
    2022-06-06
  • java基于servlet使用组件smartUpload实现文件上传

    java基于servlet使用组件smartUpload实现文件上传

    这篇文章主要介绍了java基于servlet使用组件smartUpload实现文件上传,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • SpringBoot热重启配置详解

    SpringBoot热重启配置详解

    在本篇文章里小编给大家分享的是关于SpringBoot热重启配置知识点内容,需要的朋友们可以学习下。
    2020-02-02
  • 一文搞懂Java的ThreadPoolExecutor原理

    一文搞懂Java的ThreadPoolExecutor原理

    都说经典的就是好的,这句话放在Java的ThreadPoolExecutor上那是一点都没错,像现在数据库连接的池化实现,或者像Tomcat这种WEB服务器的线程管理,处处都有着ThreadPoolExecutor的影子,本篇文章将结合源码实现,对ThreadPoolExecutor的原理进行一个深入学习
    2023-06-06
  • 基于jmeter实现跨线程组传递token过程图解

    基于jmeter实现跨线程组传递token过程图解

    这篇文章主要介绍了基于jmeter实现跨线程组传递token,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Java Stream常用方法合集(超详细)

    Java Stream常用方法合集(超详细)

    Stream API 提供了一种更为简洁高效的的方式来处理集合数据,  可读性较高, 所以本文为大家整理了Java Stream中的常用方法,希望对大家有所帮助
    2023-07-07
  • Spring Boot中防止递归查询的两种方式

    Spring Boot中防止递归查询的两种方式

    这篇文章主要给大家介绍了关于Spring Boot中防止递归查询的两种方式,两种方式分别是在application.properties中配置和在entity中添加注解,都给出了详细的示例代码,需要的朋友们下面来一起看看吧。
    2017-06-06

最新评论