最近项目中需要使用多个数据源完成业务,经过多方寻找资料和亲自测试,现在整理一下资料。本文参考:https://www.cnblogs.com/hsbt2333/p/9347249.html
1.在yml中配置多个数据源访问连接
server: port: 8099 #配置数据源的属性 spring: datasource: druid: db1: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/standarddb?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai username: root password: ******** db2: url: jdbc:mysql://IP:3306/rebiaoserver?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true username: root password: ******** driver-class-name: com.mysql.cj.jdbc.Driver #监控配置 stat-view-servlet: enabled: true login-username: root login-password: roo #thymeleaf的配置 thymeleaf: cache: false enabled: true #设置开发环境 profiles: active: dev #时区转换 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 #redis redis: database: 0 host: 127.0.0.1 #password: 123 port: 6379 timeout: 3000 # 连接超时时间 单位 ms(毫秒) # cluster: # nodes: 10.3.1.4:7000,10.3.1.4:7001,...,10.3.1.4:7008 #配置mybatisplus mybatis-plus: mapper-locations: - classpath:mapper/*/*Mapper.xml global-config: db-config: id-type: auto logic-delete-value: 1 logic-not-delete-value: 0 banner: true configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 分页插件 pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql
2. 建立数据源枚举类DataSourceEnum
package com.ckfuture.pro.DBSource; /** * @description: 多数据源枚举 * @author: CKFuture * @since: 2021-11-09 13:33 * @version: v1.0 * @LastEditTime: * @LastEditors: * @copyright: hrbckfuture.com */ public enum DataSourceEnum { DB1("db1"),DB2("db2"); private String value; DataSourceEnum(String value){this.value=value;} public String getValue() { return value; } }
3. 建立DataSourceContextHolder类
package com.ckfuture.pro.DBSource; 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(); } }
4. 建立MultipleDataSource类
package com.ckfuture.pro.DBSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class MultipleDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); } }
5.建立DataSource注解
package com.ckfuture.pro.annotation; import com.ckfuture.pro.DBSource.DataSourceEnum; import java.lang.annotation.*; /** * @description: DataSource注解 * @author: CKFuture * @since: 2021-11-09 13:35 * @version: v1.0 * @LastEditTime: * @LastEditors: * @copyright: hrbckfuture.com */ @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { DataSourceEnum value() default DataSourceEnum.DB1; }
6.建立DataSourceAspect类
package com.ckfuture.pro.DBSource; import com.ckfuture.pro.annotation.DataSource; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.After; 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; @Component @Slf4j @Aspect @Order(-1) public class DataSourceAspect { @Pointcut("@within(com.ckfuture.pro.annotation.DataSource) || @annotation(com.ckfuture.pro.annotation.DataSource)") public void pointCut(){ } @Before("pointCut() && @annotation(dataSource)") public void doBefore(DataSource dataSource){ log.info("选择数据源---"+dataSource.value().getValue()); DataSourceContextHolder.setDataSource(dataSource.value().getValue()); } @After("pointCut()") public void doAfter(){ DataSourceContextHolder.clear(); } }
7.建立配置类MyBatiesPlusConfiguration
package com.ckfuture.pro.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.plugins.PerformanceInterceptor; import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;*/ import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import com.ckfuture.pro.DBSource.DataSourceEnum; import com.ckfuture.pro.DBSource.MultipleDataSource; 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.context.annotation.Profile; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @Configuration @MapperScan("com.ckfuture.pro.*.*.dao") public class MyBatiesPlusConfiguration { @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(); } /** * 动态数据源配置 * @return */ @Bean @Primary public DataSource multipleDataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") 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; } }
8.使用数据源1
只需要在服务实现类的方法上添加注解@DataSource(DataSourceEnum.DB1)即可。
9.使用数据源2
只需要在服务实现类的方法上添加注解@DataSource(DataSourceEnum.DB2)即可。
这里本人抛砖引玉,个人建议还是尽量不要在springboot中使用多数据源,第一是比较麻烦,第二是不安全,还是建议使用springcloud。