配置了一下druid的多數據源配置,嘗試了不少方法,Spring boot關於對Mysql和Sqlite多數據源的配置,記錄下來:java
涉及技術點:mysql
Springboot
+ Druid
+ Mysql
+Sqlite
git
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