SpringBoot配置多數據源Mysql+Sqlite

​ 配置了一下druid的多數據源配置,嘗試了不少方法,Spring boot關於對Mysql和Sqlite多數據源的配置,記錄下來:java

涉及技術點:mysql

Springboot + Druid + Mysql +Sqlitegit

1、引入Jar包:

<!--Spring Boot依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.1.8.RELEASE</version>
</dependency>
<!--MYSQL鏈接依賴-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>
<!--阿里數據源鏈接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<!--sqlite依賴-->
<dependency>
    <groupId>org.xerial</groupId>
    <artifactId>sqlite-jdbc</artifactId>
    <version>3.28.0</version>
</dependency>
<!--aspects依賴-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>

2、配置參數:

spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        #druid相關配置
        druid:
            one:
                name: ds_mysql
                driver-class-name: com.mysql.cj.jdbc.Driver
                #基本屬性
                url: @jdbc.url@
                username: @jdbc.username@
                password: @jdbc.password@
                test-while-idle: false
            two:
                name: ds_sqlite
                driver-class-name: org.sqlite.JDBC
                #基本屬性
                url: jdbc:sqlite:db/test.db
                username: test
                password: test
                test-while-idle: false
            use-global-data-source-stat: true
            #監控統計攔截的filters
            filters: stat
            #配置初始化大小/最小/最大
            initial-size: 2
            min-idle: 2
            max-active: 20
            #獲取鏈接等待超時時間
            max-wait: 60000
            #間隔多久進行一次檢測,檢測須要關閉的空閒鏈接
            time-between-eviction-runs-millis: 60000
            #一個鏈接在池中最小生存的時間
            min-evictable-idle-time-millis: 300000
            validation-query: SELECT 'x' FROM DUAL
            # mysql須要設置校驗
            # 指明是否在從池中取出鏈接前進行檢驗,若是檢驗失敗,則從池中去除鏈接並嘗試取出另外一個.注意: 設置爲true後若是要生效,validationQuery參數必須設置爲非空字符串
            test-while-idle: false
            # 指明是否在歸還到池中前進行檢驗  注意: 設置爲true後若是要生效,validationQuery參數必須設置爲非空字符串
            test-on-borrow: false
            # 指明鏈接是否被空閒鏈接回收器(若是有)進行檢驗.若是檢測失敗,則鏈接將被從池中去除. 注意: 設置爲true後若是要生效,validationQuery參數必須設置爲非空字符串
            test-on-return: false
            #打開PSCache,並指定每一個鏈接上PSCache的大小。oracle設爲true,mysql設爲false。分庫分表較多推薦設置爲false
            pool-prepared-statements: false

(參數配置,可參考: https://gitee.com/wenshao/druid/tree/master/druid-spring-boot-starter)github

3、編寫配置文件:

一、定義數據源名稱常量 :

package com.meng.scaffold.config.datasource;

/**
 * @Description: 數據源名稱
 * @author: MengW9
 * @Date: 2019-11-28
 * @Time: 10:26
 */
public interface DataSourceNames {
    String ONE = "ONE";
    String TWO = "TWO";
}

二、建立動態數據源:

package com.meng.scaffold.config.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.Map;

/**
 * @program: scaffold
 * @description: 動態數據源
 * @author: MengW9
 * @create: 2019-11-28 10:26
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    /**
     * 配置DataSource, defaultTargetDataSource爲主數據庫
     */
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }

}

三、動態數據源配置:

package com.meng.scaffold.config.datasource;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
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 javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;


/**
 * @program: scaffold
 * @description: 多數據源配置
 * @author: MengW9
 * @create: 2019-11-28 10:16
 **/
@Configuration
public class DynamicDataSourceConfig {

    /**
     * 建立 DataSource Bean
     */
    @Bean("oneDataSource")
    @ConfigurationProperties("spring.datasource.druid.one")
    public DataSource oneDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean("twoDataSource")
    @ConfigurationProperties("spring.datasource.druid.two")
    public DataSource twoDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 若是還有數據源,在這繼續添加 DataSource Bean
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource oneDataSource, DataSource twoDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>(2);
        targetDataSources.put(DataSourceNames.ONE, oneDataSource);
        targetDataSources.put(DataSourceNames.TWO, twoDataSource);
        // 還有數據源,在targetDataSources中繼續添加
        System.out.println("DataSources:" + targetDataSources);
        return new DynamicDataSource(oneDataSource, targetDataSources);
    }

}

四、定義動態數據源註解:

package com.meng.scaffold.config.datasource;

import java.lang.annotation.*;

/**
 * @description: 多數據源註解
 * @author: MengW9
 * @create: 2019-11-28 10:31
 **/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default DataSourceNames.ONE;
}

五、設置數據源 AOP 代理:

package com.meng.scaffold.config.datasource;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @description: 數據源AOP切面處理
 * @author: MengW9
 * @create: 2019-11-28 10:33
 **/
@Aspect
@Component
public class DataSourceAspect implements Ordered {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 切點: 全部配置 DataSource 註解的方法
     */
    @Pointcut("@annotation(com.meng.scaffold.config.datasource.DataSource)")
    public void dataSourcePointCut() {
    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource ds = method.getAnnotation(DataSource.class);
        // 經過判斷 DataSource 中的值來判斷當前方法應用哪一個數據源
        DynamicDataSource.setDataSource(ds.value());
        System.out.println("當前數據源: " + ds.value());
        logger.debug("set datasource is " + ds.value());
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

4、修改啓動文件:

package com.meng.scaffold;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Import;

import com.gy.fast.common.config.data.DynamicDataSourceConfig;


**
 * 動態數據源配置,須要將自有的配置依賴(DynamicDataSourceConfig),將原有的依賴去除(DataSourceAutoConfiguration)
 * exclude = DataSourceAutoConfiguration.class
 * @author Meng
 */
@Import({DynamicDataSourceConfig.class})
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class DeviceApplication {
	public static void main(String[] args) {
		SpringApplication.run(DeviceApplication.class, args);
	}
}

5、配置完成, 進行測試:

測試接口編寫:web

package com.meng.scaffold.service;

import com.meng.scaffold.config.datasource.DataSource;
import com.meng.scaffold.config.datasource.DataSourceNames;
import com.meng.scaffold.dao.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @description: 測試多數據源
 * @author: MengW9
 * @create: 2019-11-28 10:39
 **/
@Service
public class DataSourceTestService {

    @Autowired
    private UserService userService;

    public User test1(Long userId) {
        return userService.selectById(userId);
    }

    /**
     * @Description: 多數據註解必須放在接口實現類的上面
     * @Param: [userId]
     * @Author: MengW9
     */
    @DataSource(DataSourceNames.TWO)
    public User test2(Long userId) {
        return userService.selectById(userId);
    }

}

編寫測試類:spring

package com.meng.scaffold;


import org.apache.commons.lang3.builder.ToStringBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.meng.scaffold.dao.User;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DynamicDataSourceTest {
    @Autowired
    private DataSourceTestService dataSourceTestService;
    
    @Test
    public void test(){
        // 數據源ONE
        SysUser user1 = dataSourceTestService.test1(1L);
        System.out.println(ToStringBuilder.reflectionToString(user1));

        // 數據源TWO
        SysUser user2 = dataSourceTestService.test2(1L);
        System.out.println(ToStringBuilder.reflectionToString(user2));

        // 數據源ONE
        SysUser user3 = dataSourceTestService.test1(1L);
        System.out.println(ToStringBuilder.reflectionToString(user3));
    }
    
}

代碼地址:Git倉庫sql

</br>數據庫

參考:apache

http://www.javashuo.com/article/p-vtsbwrzd-gx.htmloracle

相關文章
相關標籤/搜索