zoukankan      html  css  js  c++  java
  • springboot+druid+mybatis plus的多数据源配置

    https://www.jianshu.com/p/ff5af6c59365

    多数据源配置,在我们集成多个系统或者对接的时候经常会用到,结合springboot、druid提供了比较方便的集成方案。

    思路:
    1、yml中配置多个数据源信息
    2、通过AOP切换不同数据源
    3、配合mybatis plus使用


    1、yml配置

    spring:
      aop:
          proxy-target-class: true
          auto: true
      datasource:
        druid:
          db1:
            url: jdbc:mysql://localhost:3306/eboot
            username: root
            password: root
            driver-class-name: com.mysql.jdbc.Driver
            initialSize: 5
            minIdle: 5
            maxActive: 20
          db2:
            url: jdbc:oracle:thin:@192.168.136.222:ORCL
            username: sa
            password: sa123456
            driver-class-name: oracle.jdbc.OracleDriver
            initialSize: 5
            minIdle: 5
            maxActive: 20
          db3:
            url: jdbc:oracle:thin:@192.168.136.223:ORCL
            username: sb
            password: sb123456
            driver-class-name: oracle.jdbc.OracleDriver
            initialSize: 5
            minIdle: 5
            maxActive: 20
    

    2、启动加载多个数据源

    下面mybatis plus的全局配置被注掉了,因为同样可以在yml中配置也可以

    package com.df.openapi.config;
    
    import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
    import com.baomidou.mybatisplus.MybatisConfiguration;
    import com.baomidou.mybatisplus.entity.GlobalConfiguration;
    import com.baomidou.mybatisplus.mapper.LogicSqlInjector;
    import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
    import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
    import com.df.openapi.config.db.DBTypeEnum;
    import com.df.openapi.config.db.DynamicDataSource;
    import com.df.openapi.config.db.MyMetaObjectHandler;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.type.JdbcType;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author 小尘哥
     */
    @EnableTransactionManagement
    @Configuration
    @MapperScan("com.df.openapi.**.mapper.db*")
    public class MybatisPlusConfig {
    
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            paginationInterceptor.setLocalPage(true);
            return paginationInterceptor;
        }
    
        @Bean(name = "db1")
        @ConfigurationProperties(prefix = "spring.datasource.druid.db1")
        public DataSource db1() {
            return DruidDataSourceBuilder.create().build();
        }
    
        @Bean(name = "db2")
        @ConfigurationProperties(prefix = "spring.datasource.druid.db2")
        public DataSource db2() {
            return DruidDataSourceBuilder.create().build();
        }
    
        @Bean(name = "db3")
        @ConfigurationProperties(prefix = "spring.datasource.druid.db3")
        public DataSource db3() {
            return DruidDataSourceBuilder.create().build();
        }
    
        /**
         * 动态数据源配置
         *
         * @return
         */
        @Bean
        @Primary
        public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
                                             @Qualifier("db2") DataSource db2,
                                             @Qualifier("db3") DataSource db3) {
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DBTypeEnum.db1.getValue(), db1);
            targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
            targetDataSources.put(DBTypeEnum.db3.getValue(), db3);
            dynamicDataSource.setTargetDataSources(targetDataSources);
            dynamicDataSource.setDefaultTargetDataSource(db2);
            return dynamicDataSource;
        }
    
        @Bean("sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
            sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2(),db3()));
    
            MybatisConfiguration configuration = new MybatisConfiguration();
            configuration.setJdbcTypeForNull(JdbcType.NULL);
            configuration.setMapUnderscoreToCamelCase(true);
            configuration.setCacheEnabled(false);
            sqlSessionFactory.setConfiguration(configuration);
            //PerformanceInterceptor(),OptimisticLockerInterceptor()
            //添加分页功能
            sqlSessionFactory.setPlugins(new Interceptor[]{
                    paginationInterceptor()
            });
    //        sqlSessionFactory.setGlobalConfig(globalConfiguration());
            return sqlSessionFactory.getObject();
        }
    
     /*   @Bean
        public GlobalConfiguration globalConfiguration() {
            GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
            conf.setLogicDeleteValue("-1");
            conf.setLogicNotDeleteValue("1");
            conf.setIdType(0);
            conf.setMetaObjectHandler(new MyMetaObjectHandler());
            conf.setDbColumnUnderline(true);
            conf.setRefresh(true);
            return conf;
        }*/
    }
    
    

    3、DBType枚举类

    package com.df.openapi.config.db;
    
    public enum DBTypeEnum {
    
        db1("db1"), db2("db2"), db3("db3");
        private String value;
    
        DBTypeEnum(String value) {
            this.value = value;
        }
    
        public String getValue() {
            return value;
        }
    }
    

    4、动态数据源决策

    package com.df.openapi.config.db;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
            return  DbContextHolder.getDbType();
        }
    }
    

    5、设置、获取数据源

    package com.df.openapi.config.db;
    
    public class DbContextHolder {
    
        private static final ThreadLocal contextHolder = new ThreadLocal<>();
        /**
         * 设置数据源
         * @param dbTypeEnum
         */
        public static void setDbType(DBTypeEnum dbTypeEnum) {
            contextHolder.set(dbTypeEnum.getValue());
        }
    
        /**
         * 取得当前数据源
         * @return
         */
        public static String getDbType() {
            return (String) contextHolder.get();
        }
    
        /**
         * 清除上下文数据
         */
        public static void clearDbType() {
            contextHolder.remove();
        }
    }
    
    

    6、AOP实现的数据源切换

    @Order设置的足够小是为了让他先执行

    package com.df.openapi.config.db;
    
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    /**
     * @author 迪富
     */
    @Component
    @Order(value = -100)
    @Slf4j
    @Aspect
    public class DataSourceSwitchAspect {
    
        @Pointcut("execution(* com.df.openapi.*.mapper.db1..*.*(..))")
        private void db1Aspect() {
        }
    
        @Pointcut("execution(* com.df.openapi.*.mapper.db2..*.*(..))")
        private void db2Aspect() {
        }
    
        @Pointcut("execution(* com.df.openapi.*.mapper.db3..*.*(..))")
        private void db3Aspect() {
        }
    
        @Before("db1Aspect()")
        public void db1() {
            log.info("切换到db1 数据源...");
            DbContextHolder.setDbType(DBTypeEnum.db1);
        }
    
        @Before("db2Aspect()")
        public void db2() {
            log.info("切换到db2 数据源...");
            DbContextHolder.setDbType(DBTypeEnum.db2);
        }
    
        @Before("db3Aspect()")
        public void db3() {
            log.info("切换到db3 数据源...");
            DbContextHolder.setDbType(DBTypeEnum.db3);
        }
    }
    
    

    7、mapper层结构

     
    根据dbx的实现数据源切换.png

    8、写一个service测试一下

    可以看到下面的两个Mapper分别来自db1和db2

    package com.df.openapi.system.service.impl;
    
    import com.df.openapi.system.entity.PtDict;
    import com.df.openapi.system.entity.SysDict;
    import com.df.openapi.system.mapper.db1.PtDictMapper;
    import com.df.openapi.system.mapper.db2.SysDictMapper;
    import com.df.openapi.system.service.IDictService;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class DictServiceImpl implements IDictService {
    
        @Resource
        private PtDictMapper ptDictMapper;
    
        @Resource
        private SysDictMapper sysDictMapper;
    
    
        @Override
        public void getById(String id) {
            PtDict dict = ptDictMapper.selectById("2bf6257fc8fe483c84c1ad7e89d632f6");
            SysDict sysDict = sysDictMapper.getById("49");
            System.out.println("123");
        }
    }
    
    

    9、简单的单元测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class OpenApiApplicationTests {
    
        @Autowired
        private IDictService dictService;
    
        @Test
        public void contextLoads() {
        }
    
        @Test
        public void test() {
            dictService.getById("1");
        }
    }
    

    10、测试结果

     
    取到两个数据库的数据.png

    参考上面的方法,可以随意配置三四五六七八九十个数据源都没问题,有问题欢迎随时来撩!



    作者:小尘哥
    链接:https://www.jianshu.com/p/ff5af6c59365
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    剑指Offers 题目1384:二维数组中的查找
    剪切板获取图片并上传
    VSCode TSlint + Prettier 实现代码的格式化
    Element Table 合并列
    Linux下安装Redis
    transfer 增加拖拽排序组件封装
    在VSCode中使用Git处理文件冲突(pull不能从服务器拉取代码)
    Vue的 transition在v-for的嵌套下怎么用
    Vant的picker组件放在popup中,导致ref获取不到
    小工具
  • 原文地址:https://www.cnblogs.com/zuokun/p/13552525.html
Copyright © 2011-2022 走看看