两种多数据源的配置

SpringBoot项目配置多数据源

​ 在工作中你一定遇到过这么一个问题,一个功能涉及到多张表的CRUD,而这些表又来源于不同的数据库,关键是可能数据库的类型也可能不同,可能是mysql,也可能是oracle、postgre这样的数据源。而传统使用mybatis配置数据源默认只支持配置一个数据库,这显然不能满足我们的需求,所以我们现在需要了解一下怎么配置多数据源。

​ 配置多数据源的方式其实有很多,我这里先暂时说一下我常使用的两种方式,第一种就是不使用mybatis这类orm框架,而是使用原生的JDBCTemplate来配置多数据源。第二种就是使用aop的方式来修改mybatis默认配置数据源的,自己自定义数据源,达到动态配置数据源的目的。

一、JDBCTemplate 配置多数据源

第一种使用jdbctemplate具体步骤如下:

  1. 导入maven包

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  2. 在application.yml里面配置数据源四大金刚

    spring:
      datasource:
        druid:
          pethome:
            jdbc-url: jdbc:mysql:///pethome?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
            username: root
            password: xxx
            driver-class-name: com.mysql.jdbc.Driver
            type: com.alibaba.druid.pool.DruidDataSource
          book:
            jdbc-url: jdbc:mysql:///book_manager?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
            username: root
            password: 123456
            driver-class-name: com.mysql.jdbc.Driver
            type: com.alibaba.druid.pool.DruidDataSource
    
  3. 配置了四大金刚过后,那么就可以直接引用四大金刚,配置数据源了。首先就是需要先创建一个配置类,打上@Configuration注解,然后写入以下代码。这里@Primary表示使用pethome为默认的数据源,如果不加此注解,会报有两个数据源异常。

    	@Bean(name = "pethome")
    	@Primary//主数据源
    	@ConfigurationProperties(prefix = "spring.datasource.druid.pethome")
    	public DataSource pethome() {
    		return DataSourceBuilder.create().build();
    	}
    
    	@Bean(name = "book")
    	@ConfigurationProperties(prefix = "spring.datasource.druid.book")
    	public DataSource book() {
    		return DataSourceBuilder.create().build();
    	}
    
  4. 配置完过后就可以直接使用@Resource(name=“名”)注入你想使用的数据源啦。

    @Resource(name = "pethome")
    private DataSource pethome;
    @Resource(name = "book")
    private DataSource book;
    @RequestMapping(value="/test1",method= RequestMethod.POST)
    @ApiOperation(value = "测试jdbc", notes = "测试")
    public List<Map<String,Object>> test(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(pethome);
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * FROM 表");
        System.out.println(maps);
        return maps;
    }
    @RequestMapping(value="/test2",method= RequestMethod.POST)
    @ApiOperation(value = "测试jdbc2", notes = "测试")
    public List<Map<String,Object>> test2(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(book);
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * FROM 表");
        System.out.println(maps);
        return maps;
    }
    

二、SpringBoot+Mybatis+AOP配置多数据源

第二种的主要配置如下:

  1. 导入maven包

     		<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>2.3</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!-- 增加postgresql的支持 -->
            <dependency>
                <groupId>org.postgresql</groupId>
                <artifactId>postgresql</artifactId>
            </dependency>
    
            <!-- 增加oracle的支持 -->
            <dependency>
                <groupId>com.oracle</groupId>
                <artifactId>ojdbc6</artifactId>
                <version>11.2.0.3</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus</artifactId>
                <version>2.1.8</version>
            </dependency>
    
  2. 在application.yml里面配置数据源四大金刚

    spring:
      datasource:
        druid:
          pethome:
            jdbc-url: jdbc:mysql:///pethome?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
            username: root
            password: xxx
            driver-class-name: com.mysql.jdbc.Driver
            type: com.alibaba.druid.pool.DruidDataSource
          book:
            jdbc-url: jdbc:mysql:///book_manager?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
            username: root
            password: 123456
            driver-class-name: com.mysql.jdbc.Driver
            type: com.alibaba.druid.pool.DruidDataSource
    
  3. 创建Datasource注解

    @Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface DataSource {
    
        DataSourceEnum value() default DataSourceEnum.DB1;
    }
    
  4. 创建DataSourceEnum常量

    public enum DataSourceEnum {
    
        DB1("book"),DB2("pethome");
    
        private String value;
    
        DataSourceEnum(String value){this.value=value;}
    
        public String getValue() {
            return value;
        }
    }
    
  5. 创建DataSourceContextHolder

    public class DataSourceContextHolder {
    
        private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();
    
        /**
         *  设置数据源
         * @param db
         */
        public static void setDataSource(String db){
            contextHolder.set(db);
        }
    
        /**
         * 取得当前数据源
         * @return
         */
        public static String getDataSource(){
            return contextHolder.get();
        }
    
        /**
         * 清除上下文数据
         */
        public static void clear(){
            contextHolder.remove();
        }
    }
    
  6. 设置MultipleDataSource,里面的determineCurrentLookupKey是决定当前使用数据源,然后返回当前数据源的key。

    public class MultipleDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceContextHolder.getDataSource();
        }
    }
    
  7. 为注解增加aop配置

    @Component
    @Aspect
    @Order(-1)
    public class DataSourceAspect {
    
        @Pointcut("@within(cn.antu.dynamic.annotation.DataSource) || @annotation(cn.antu.dynamic.annotation.DataSource)")
        public void pointCut(){
    
        }
    
        @Before("pointCut() && @annotation(dataSource)")
        public void doBefore(DataSource dataSource){
            DataSourceContextHolder.setDataSource(dataSource.value().getValue());
        }
    
        @After("pointCut()")
        public void doAfter(){
            DataSourceContextHolder.clear();
        }
    }
    
  8. 修改mybatis的默认配置

    @Configuration // 注解到spring容器中
    @MapperScan(basePackages = "cn.antu.dynamic.mapper.*")
    public class MybatisDataSource {
    
    	/*
    	 * 分页插件,自动识别数据库类型 多租户,请参考官网【插件扩展】
    	 */
    	@Bean
    	public PaginationInterceptor paginationInterceptor() {
    		PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    		// 开启 PageHelper 的支持
    		paginationInterceptor.setLocalPage(true);
    		return paginationInterceptor;
    	}
    
    	/**
    	 * SQL执行效率插件
    	 */
    //	@Bean
    //	@Profile({ "dev", "qa" }) // 设置 dev test 环境开启
    //	public PerformanceInterceptor performanceInterceptor() {
    //		PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    //		performanceInterceptor.setMaxTime(1000);
    //		performanceInterceptor.setFormat(true);
    //		return performanceInterceptor;
    //	}
    
    	/**
    	 * 返回data1数据库的数据源
    	 * 
    	 * @return
    	 */
    	@Bean(name = "pethome")
    	@Primary//主数据源
    	@ConfigurationProperties(prefix = "spring.datasource.druid.pethome")
    	public DataSource pethome() {
    		return DataSourceBuilder.create().build();
    	}
    
    	@Bean(name = "book")
    	@ConfigurationProperties(prefix = "spring.datasource.druid.book")
    	public DataSource book() {
    		return DataSourceBuilder.create().build();
    	}
    
    	@Bean("sqlSessionFactory")
    	public SqlSessionFactory sqlSessionFactory() throws Exception {
    		MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
    		sqlSessionFactory.setDataSource(multipleDataSource(primary(), secondary()));
    		// sqlSessionFactory.setMapperLocations(new
    		// PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml"));
    
    		MybatisConfiguration configuration = new MybatisConfiguration();
    		// configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
    		configuration.setJdbcTypeForNull(JdbcType.NULL);
    		configuration.setMapUnderscoreToCamelCase(true);
    		configuration.setCacheEnabled(false);
    		sqlSessionFactory.setConfiguration(configuration);
    		sqlSessionFactory.setPlugins(new Interceptor[] { // PerformanceInterceptor(),OptimisticLockerInterceptor()
    				paginationInterceptor() // 添加分页功能
    		});
    		// sqlSessionFactory.setGlobalConfig(globalConfiguration());
    		return sqlSessionFactory.getObject();
    	}
    
    	/**
    	 * 动态数据源配置
    	 * 
    	 * @return
    	 */
    	@Bean
    	@Primary
    	public DataSource multipleDataSource(@Qualifier("book") DataSource db1,
    			@Qualifier("pethome") DataSource db2) {
    		MultipleDataSource multipleDataSource = new MultipleDataSource();
    		Map<Object, Object> targetDataSources = new HashMap<>();
    		targetDataSources.put(DataSourceEnum.DB1.getValue(), db1);
    		targetDataSources.put(DataSourceEnum.DB2.getValue(), db2);
    		// 添加数据源
    		multipleDataSource.setTargetDataSources(targetDataSources);
    		// 设置默认数据源
    		multipleDataSource.setDefaultTargetDataSource(db1);
    		return multipleDataSource;
    	}
    }
    

具体流程逻辑

​ 上面这些代码网上随处可见,我一时copy过来的,直接用就可以了,具体流程我分析了一下,如下:

​ 当我们使用了@DataSource(“book”)注解过后,切面类的@Before方法就会把当前指定的book数据源设置到当前线程的DataSourceContextHolder里面,然后MultipleDataSource里面的determineCurrentLookupKey()方法就是指定当前数据源为@DataSource(“book”)指定的book数据源。又因为我们在MybatisDataSource里面配置了multipleDataSource.setTargetDataSources(targetDataSources);targetDataSources是一个map,key为数据源名称,value为数据源bean对象。而determineCurrentLookupKey返回是key,系统最终会通过key找到对应的数据源。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值