springboot 配置动态切换多数据源

springboot 配置动态切换多数据源

近来由于公司的一个项目需要用到多数据源,在其中遇到了一些问题,特在此记录。关于mybatis的配置,请自行百度。

目录

配置多数据源

配置连接数据库信息
在yml中或者自定义一个配置文件properties,填入以下信息
//数据源1,jurisdiction用于区别不同数据源
spring.datasource.jurisdiction.driverClassName=
spring.datasource.jurisdiction.url=
spring.datasource.jurisdiction.username=
spring.datasource.jurisdiction.password=
//数据源2,base用于区别不同数据源
spring.datasource.base.driverClassName=
spring.datasource.base.url=
spring.datasource.base.username=
spring.datasource.base.password=
定义存储数据源key值的类
新建一个DataSourceContextHolder.java的类,代码如下:
@Slf4j
public class DataSourceContextHolder {
    //线程安全,存储数据源的key值
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    //设置当前的数据源
    public static void setDatasource(String dbType){
        log.info("切换到 [ {} ] 数据源",dbType);
        contextHolder.set(dbType);
    }

    //获取当前数据源
    public static String getDatasource(){
        return contextHolder.get();
    }
    //清除当前数据源
    public static void clearDatasource(){
        contextHolder.remove();
    }
}
定义数据源的常量类
新建一个DataSourceType.java的枚举类,添加需要用到的数据源的key值。
定于数据源注解
用于注解方法或注解,切换数据源,设置默认数据源的key,代码如下:
@Target({ElementType.ANNOTATION_TYPE,ElementType.METHOD})
public @interface DataSource {

    //DataSourceType为自定义的数据源常量类
    //JURISDICTION为我的系统的主数据源的key
    DataSourceType value() default DataSourceType.JURISDICTION;

}
定义数据源注解的切面类
新建一个DataSourceHandle.java类,用于获取@DataSource注解的数据源信息,切换数据源,代码如下:
/**
 * 需要将该类注册为组件,注册到spring中,让spring管理该类
 */
@Component
@Aspect
public class DataSourceHandle{

    //定义切面,指被@DataSource注解的方法被拦截
    @Pointcut("@annotation(com.example.demo.aspect.DataSource)")
    public void pointcut(){ }

    //该方法在进入被@DataSource注解的方法前执行,切换数据源
    @Before("pointcut()")
    public void changeDataSource(JoinPoint point){
        Class clazz = point.getTarget().getClass();
        String methodName = point.getSignature().getName();
        Class[] classes = ((MethodSignature) point.getSignature()).getParameterTypes();

        try {
            Method method = clazz.getMethod(methodName,classes);
            if (method.isAnnotationPresent(DataSource.class)){
                DataSource dataSource = method.getAnnotation(DataSource.class);
                DataSourceType dataSourceType = dataSource.value();
                DataSourceContextHolder.setDatasource(dataSourceType.getValue());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
    //该方法在进入被@DataSource注解的方法前执行,清除当前数据源
    @After("pointcut()")
    public void clearDatasource(){
        DataSourceContextHolder.clearDatasource();
    }
}
定义数据源配置类
新建一个DruidConfiguration.java的类,添加需要使用的数据源,及动态数据源。代码如下:
@Configuration
@PropertySource(value = "classpath:jdbc.properties")//自定义的数据库连接配置文件
public class DruidConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(DruidConfiguration.class);

    //数据源1,该数据源连接配置的前缀为spring.datasource.jurisdiction
    @Bean("jurisdictionDatasource")
    @ConfigurationProperties(prefix = "spring.datasource.jurisdiction")
    public DataSource jurDataSource() {
        return new DruidDataSource();
    }

    //数据源2,该数据源连接配置的前缀为spring.datasource.base
    @Bean("beanDatasource")
    @ConfigurationProperties(prefix = "spring.datasource.base")
    public DataSource baseDatasource(){
        return new DruidDataSource();
    }

    //动态数据源
    @Bean("dynamicDataSource")
    @Primary//表示优先使用该bean
    public DataSource dynamicDataSource(){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //配置动态数据源的主数据源
        dynamicDataSource.setDefaultTargetDataSource(jurDataSource());
        //配置动态数据源中使用到的数据源
        Map<Object,Object> dataSources = new HashMap<>(2);
        dataSources.put(DataSourceType.JURISDICTION.getValue(),jurDataSource());
        dataSources.put(DataSourceType.BASE.getValue(),baseDatasource());
        dynamicDataSource.setTargetDataSources(dataSources);
        return dynamicDataSource;
    }

    //配置动态使用事务
    @Bean
    public PlatformTransactionManager platformTransactionManager(){
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}
yml文件中mybatis的配置
在application.yml配置mybatis需要的.xml文件和entity包的位置,如下:
mybatis:
  mapper-locations:
  - classpath*: #.xml的位置
  type-aliases-package: #
  configuration:
    map-underscore-to-camel-case: true # 下划线转驼峰
关闭springboot自动的数据源配置
由于springboot会自动添加数据源的配置,需要关闭该功能,不然不能加载自定义的多数据源配置,可在启动类中添加下面代码:
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
部分需要的依赖包
<!--数据库需要的依赖包-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--aop需要的依赖包-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--lombok插件需要的依赖包,简化setter和getter等代码-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

到此为止,动态多数据源配置完成。

多数据源的使用
只需在需要切换数据源的方法上添加@DataSource(需要切换的数据源)即可,若果时使用主数据源,不用添加注解。

遇到的问题

dao包中的方法找不到对应的xml中的SQL语句
可能问题1:dao包中的方法与xml文件中的id对应不上
解决办法:认真对照dao文件中的方法与xml文件中id是否有单词拼写错误等

可能问题2:xml文件没有被打包
原因:springboot默认java包下是java文件,xml放在resource包中,由于xml文件与dao文件放在一起,在java包内,导致xml不能被打包。
解决办法1:把xml文件放到resource包下,修改application.yml中的xml文件的路径。
解决办法2:在pom.xml文件中加入以下代码:
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>utf-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>src/main/webapp</directory>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>
自定义数据源注解与@Transaction同时使用时不生效
可能问题:自定义数据源注解与@Transaction注解同一个方法,会先执行@Transaction注解,即获取数据源在切换数据源之前,所以会导致自定义注解失效。
解决方法:当需要使用事务及切换数据源注解时,要将自定义注解在被@Transaction注解方法的调用方
如:在service中使用@Transaction,需要在controller中使用切换数据源注解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值