springboot+Mybatis(MybatisPlus)+HikariCP多数据源动态配置(三个数据源)

springboot+Mybatis(MybatisPlus)+HikariCP多数据源动态配置(三个数据源)

我们新做的系统可能是很多个数据源,所以我闲来无事研究一下Mybatis多数据源的配置,然后连接池只要你不配置默认就是HikariCP,被称为最快速的连接池。所以我们使用HikariCP数据库连接池,需要用到aop动态切换,话不多说,上代码了。 1.pom.xml大概要使用的包,仅供参考,我也需要自动生成代码所以也会有MybatisPlus的包
<!-- ##################### mybatis ###########################-->
  • <!-- mybatis分页插件 -->
  • <dependency>
  • <groupId>com.github.pagehelper</groupId>
  • <artifactId>pagehelper</artifactId>
  • <version> 4.1.0</version>
  • </dependency>
  • <!-- mybatis-plus 核心库 -->
  • <dependency>
  • <groupId>com.baomidou</groupId>
  • <artifactId>mybatis-plus</artifactId>
  • <version> 2.1.8</version>
  • </dependency>
  • <!-- mybatis-plus-模板引擎自动生成代码用 -->
  • <dependency>
  • <groupId>org.apache.velocity</groupId>
  • <artifactId>velocity-engine-core</artifactId>
  • <version> 2.0</version>
  • </dependency>
  • <!-- mybatis-springboot -->
  • <dependency>
  • <groupId>org.mybatis.spring.boot</groupId>
  • <artifactId>mybatis-spring-boot-starter</artifactId>
  • <version> 1.3.2</version>
  • </dependency>
  • <!-- ##################### mybatis end ###########################-->
  • <!-- springboot-aop -->
  • <dependency>
  • <groupId>org.springframework.boot</groupId>
  • <artifactId>spring-boot-starter-aop</artifactId>
  • </dependency>
  • <dependency>
  • <groupId>org.assertj</groupId>
  • <artifactId>assertj-core</artifactId>
  • </dependency>
  • 2.然后就是yml的配置。

    
     
     
    1. spring:
    2. aop:
    3. proxy-target- class: true
    4. # proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。
    5. #如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。
    6. auto: true
    7. application:
    8. name: gsa-geographic-system
    9. datasource:
    10. ds0:
    11. jdbc-url: jdbc:mysql://localhost:3306/xdclass?useUnicode= true&characterEncoding=utf- 8&useSSL= false
    12. username: root
    13. password: root
    14. driver- class-name: com.mysql.jdbc.Driver
    15. ds1:
    16. jdbc- url: jdbc: mysql:// localhost:3306/ mall_0? useUnicode= true&characterEncoding=utf- 8&useSSL= false
    17. username: root
    18. password: root
    19. driver- class-name: com.mysql.jdbc.Driver
    20. ds2:
    21. jdbc- url: jdbc: mysql:// localhost:3306/ babytun? useUnicode= true&characterEncoding=utf- 8&useSSL= false
    22. username: root
    23. password: root
    24. driver- class-name: com.mysql.jdbc.Driver

    3.以上准备好了以后就需要配置注入了,创建类MybatisPlusConfig。

    
     
     
    1. package gsa.geographic.system.config.dataSource;
    2. import com.baomidou.mybatisplus.MybatisConfiguration;
    3. import com.baomidou.mybatisplus.entity.GlobalConfiguration;
    4. import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
    5. import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
    6. import com.github.pagehelper.PageHelper;
    7. import gsa.geographic.system.enumclass.DBTypeEnum;
    8. import org.apache.ibatis.plugin.Interceptor;
    9. import org.apache.ibatis.session.SqlSessionFactory;
    10. import org.apache.ibatis.type.JdbcType;
    11. import org.springframework.beans.factory.annotation.Qualifier;
    12. import org.springframework.boot.context.properties.ConfigurationProperties;
    13. import org.springframework.boot.jdbc.DataSourceBuilder;
    14. import org.springframework.context.annotation.Bean;
    15. import org.springframework.context.annotation.Configuration;
    16. import org.springframework.context.annotation.Primary;
    17. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    18. import javax.sql.DataSource;
    19. import java.util.HashMap;
    20. import java.util.Map;
    21. import java.util.Properties;
    22. /**
    23. * 分页配置
    24. *
    25. * @Author df
    26. * @Date 2019/8/20 10:09
    27. * @Version 1.0
    28. */
    29. @Configuration
    30. public class MybatisPlusConfig {
    31. /**
    32. * mybatis-plus分页插件<br>
    33. * 文档:http://mp.baomidou.com<br>
    34. */
    35. @Bean
    36. public PaginationInterceptor paginationInterceptor() {
    37. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    38. paginationInterceptor.setDialectType( "mysql");
    39. // paginationInterceptor.setLimit(你的最大单页限制数量,默认 500 条,小于 0 如 -1 不受限制);
    40. //return new PerformanceInterceptor();
    41. return paginationInterceptor;
    42. }
    43. /**
    44. * 配置mybatis的分页插件pageHelper
    45. *
    46. * @return
    47. */
    48. @Bean
    49. public PageHelper pageHelper() {
    50. PageHelper pageHelper = new PageHelper();
    51. Properties properties = new Properties();
    52. properties.setProperty( "offsetAsPageNum", "true");
    53. properties.setProperty( "rowBoundsWithCount", "true");
    54. properties.setProperty( "reasonable", "true");
    55. properties.setProperty( "dialect", "mysql"); //配置mysql数据库的方言 pageHelper.setProperties(properties); return pageHelper; }}
    56. return pageHelper;
    57. }
    58. /**
    59. * 创建第一个数据源
    60. * @return
    61. */
    62. @Bean(name = "ds0")
    63. @ConfigurationProperties(prefix = "spring.datasource.ds0")
    64. public DataSource dataSource0() {
    65. return DataSourceBuilder.create().build();
    66. }
    67. /**
    68. * 创建第二个数据源
    69. * @return
    70. */
    71. @Bean(name = "ds1")
    72. @ConfigurationProperties(prefix = "spring.datasource.ds1")
    73. public DataSource dataSource1() {
    74. return DataSourceBuilder.create().build();
    75. }
    76. /**
    77. * 创建第三个数据源
    78. * @return
    79. */
    80. @Bean(name = "ds2")
    81. @ConfigurationProperties(prefix = "spring.datasource.ds2")
    82. public DataSource dataSource2() {
    83. return DataSourceBuilder.create().build();
    84. }
    85. /**
    86. * 动态数据源配置
    87. *
    88. * @return
    89. */
    90. @Bean
    91. @Primary
    92. public DataSource multipleDataSource(@Qualifier("ds0") DataSource ds0,
    93. @Qualifier("ds1") DataSource ds1,
    94. @Qualifier("ds2") DataSource ds2) {
    95. DynamicDataSource dynamicDataSource = new DynamicDataSource();
    96. Map<Object, Object> dataSources = new HashMap<>();
    97. dataSources.put(DBTypeEnum.DS0.getValue(), ds0);
    98. dataSources.put(DBTypeEnum.DS1.getValue(), ds1);
    99. dataSources.put(DBTypeEnum.DS2.getValue(), ds2);
    100. dynamicDataSource.setTargetDataSources(dataSources);
    101. dynamicDataSource.setDefaultTargetDataSource(ds0);
    102. return dynamicDataSource;
    103. }
    104. @Bean( "sqlSessionFactory")
    105. public SqlSessionFactory sqlSessionFactory() throws Exception {
    106. // 导入mybatissqlsession配置
    107. MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
    108. // 指明数据源
    109. sessionFactory.setDataSource(multipleDataSource(dataSource0(), dataSource1(), dataSource2()));
    110. // 指明mapper.xml位置(配置文件中指明的xml位置会失效用此方式代替,具体原因未知)
    111. sessionFactory.setMapperLocations( new PathMatchingResourcePatternResolver().getResources( "classpath*:/mapper/**Mapper.xml"));
    112. // 指明实体扫描(多个package用逗号或者分号分隔)
    113. sessionFactory.setTypeAliasesPackage( "gsa.geographic.system.entity");
    114. // 导入mybatis配置
    115. MybatisConfiguration configuration = new MybatisConfiguration();
    116. configuration.setJdbcTypeForNull(JdbcType.NULL);
    117. configuration.setMapUnderscoreToCamelCase( true);
    118. configuration.setCacheEnabled( false);
    119. sessionFactory.setConfiguration(configuration);
    120. // 添加分页功能
    121. sessionFactory.setPlugins( new Interceptor[]{
    122. paginationInterceptor()
    123. });
    124. // 导入全局配置
    125. sessionFactory.setGlobalConfig(globalConfiguration());
    126. return sessionFactory.getObject();
    127. }
    128. /**
    129. * 在代码中配置MybatisPlus替换掉application.yml中的配置
    130. *
    131. * @return
    132. */
    133. @Bean
    134. public GlobalConfiguration globalConfiguration() {
    135. GlobalConfiguration configuration = new GlobalConfiguration();
    136. configuration.setLogicDeleteValue( "-1");
    137. configuration.setLogicNotDeleteValue( "1");
    138. // 主键类型 0:数据库ID自增, 1:用户输入ID,2:全局唯一ID (数字类型唯一ID), 3:全局唯一ID UUID
    139. configuration.setIdType( 0);
    140. // 驼峰下划线转换
    141. configuration.setDbColumnUnderline( true);
    142. // 是否动态刷新mapper
    143. configuration.setRefresh( true);
    144. return configuration;
    145. }
    146. }

    4.创建动态数据源的获取类DynamicDataSource继承AbstractRoutingDataSource

    
     
     
    1. package gsa.geographic.system.config.dataSource;
    2. import gsa.geographic.system.config.dataSource.DbContextHolder;
    3. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    4. /**
    5. * @Author df
    6. * 扩展Spring的AbstractRoutingDataSource抽象类,实现动态数据源(他的作用就是动态切换数据源)
    7. * AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心,
    8. * 这里对该方法进行Override。【上下文DbContextHolder为一线程安全的ThreadLocal】
    9. * @Date 2019/9/3 15:39
    10. * @Version 1.0
    11. */
    12. public class DynamicDataSource extends AbstractRoutingDataSource {
    13. /**
    14. * 取得当前使用哪个数据源
    15. *
    16. * @return
    17. */
    18. @Override
    19. protected Object determineCurrentLookupKey() {
    20. return DbContextHolder.getDbType();
    21. }
    22. }

    5.创建获取,设置数据源的类DbContextHolder,为了线程安全使用了ThreadLocal。

    
     
     
    1. package gsa.geographic.system.config.dataSource;
    2. import gsa.geographic.system.enumclass.DBTypeEnum;
    3. /**
    4. * @Author df
    5. * @Date 2019/9/3 16:14
    6. * @Version 1.0
    7. * @description:设置,获取,清空 当前线程内的数据源变量。
    8. */
    9. public class DbContextHolder {
    10. private static final ThreadLocal contextHolder = new ThreadLocal();
    11. /**
    12. * 设置数据源
    13. *
    14. * @param dbTypeEnum
    15. */
    16. public static void setDbType(DBTypeEnum dbTypeEnum) {
    17. contextHolder.set(dbTypeEnum.getValue());
    18. }
    19. /**
    20. * 取得当前数据源
    21. *
    22. * @return
    23. */
    24. public static String getDbType() {
    25. return (String) contextHolder.get();
    26. }
    27. /**
    28. * 清除上下文数据
    29. */
    30. public static void clearDbType() {
    31. contextHolder.remove();
    32. }
    33. }

    6.创建枚举类DBTypeEnum,方便添加查看哪些枚举类

    
     
     
    1. package gsa.geographic.system.enumclass;
    2. /**
    3. * @Author df
    4. * @Date 2019/9/3 15:45
    5. * @Version 1.0
    6. * 设置数据源
    7. */
    8. public enum DBTypeEnum {
    9. DS0( "ds0"), DS1( "ds1"), DS2( "ds2");
    10. private String value;
    11. DBTypeEnum(String value) {
    12. this.value = value;
    13. }
    14. public String getValue() {
    15. return value;
    16. }
    17. }

    7.再添加一个aop切面类DataSourceSwitchAspect,这样就可以动态切换数据源了

    
     
     
    1. package gsa.geographic.system.config.dataSource;
    2. import gsa.geographic.system.enumclass.DBTypeEnum;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.aspectj.lang.JoinPoint;
    5. import org.aspectj.lang.annotation.Aspect;
    6. import org.aspectj.lang.annotation.Before;
    7. import org.aspectj.lang.annotation.Pointcut;
    8. import org.aspectj.lang.reflect.MethodSignature;
    9. import org.springframework.core.annotation.Order;
    10. import org.springframework.stereotype.Component;
    11. import java.util.Objects;
    12. /**
    13. * AOP方式动态切换数据源
    14. *
    15. * @Author df
    16. * @Date 2019/9/3 16:26
    17. * @Version 1.0
    18. */
    19. @Component
    20. @Aspect
    21. @Order(- 100) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
    22. @Slf4j
    23. public class DataSourceSwitchAspect {
    24. @Pointcut( "execution(* gsa.geographic.system.service..*.*(..))")
    25. private void dbAspect() {
    26. }
    27. @Before( "dbAspect()")
    28. public void db(JoinPoint joinPoint) {
    29. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    30. DataSourceSwitch dataSourceSwitch = methodSignature.getMethod().getAnnotation(DataSourceSwitch.class);
    31. if (Objects.isNull(dataSourceSwitch) || Objects.isNull(dataSourceSwitch.value())) {
    32. DbContextHolder.setDbType(DBTypeEnum.DS0);
    33. } else {
    34. switch (dataSourceSwitch.value().getValue()) {
    35. case "ds0":
    36. DbContextHolder.setDbType(DBTypeEnum.DS0);
    37. break;
    38. case "ds1":
    39. DbContextHolder.setDbType(DBTypeEnum.DS1);
    40. break;
    41. case "ds2":
    42. DbContextHolder.setDbType(DBTypeEnum.DS2);
    43. break;
    44. default:
    45. DbContextHolder.setDbType(DBTypeEnum.DS0);
    46. }
    47. }
    48. }
    49. }

    8.再添加一个可以供我们用注解形式的调用方式的接口。

    
     
     
    1. package gsa.geographic.system.config.dataSource;
    2. import gsa.geographic.system.enumclass.DBTypeEnum;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. /**
    8. * Service方法调用
    9. *
    10. * @Author df
    11. * @Date 2019/9/3 16:32
    12. * @Version 1.0
    13. */
    14. @Retention(RetentionPolicy.RUNTIME)
    15. @Target({ElementType.METHOD})
    16. public @interface DataSourceSwitch {
    17. DBTypeEnum value() default DBTypeEnum.DS0;
    18. }

    好了配置以上我这边反正是可以启动正常的。

    然后开始在service里边使用不同的数据源把,先给大家我的serviceImpl的示例把!这是使用第一个数据源,其实配置默认的数据源以后默认的那个数据源是可以不用写注解表名的,其他两个数据源需要写上注解。

    
     
     
    1. package gsa.geographic.system.service.impl;
    2. import gsa.geographic.system.config.dataSource.DataSourceSwitch;
    3. import gsa.geographic.system.entity.TOrder0;
    4. import gsa.geographic.system.dao.TOrder0Mapper;
    5. import gsa.geographic.system.enumclass.DBTypeEnum;
    6. import gsa.geographic.system.service.TOrder0Service;
    7. import com.baomidou.mybatisplus.service.impl.ServiceImpl;
    8. import org.springframework.beans.factory.annotation.Autowired;
    9. import org.springframework.stereotype.Service;
    10. import java.util.List;
    11. /**
    12. * <p>
    13. * 服务实现类
    14. * </p>
    15. *
    16. * @author df123
    17. * @since 2019-09-03
    18. */
    19. @Service
    20. public class TOrder0ServiceImpl extends ServiceImpl<TOrder0Mapper, TOrder0> implements TOrder0Service {
    21. @Autowired
    22. private TOrder0Mapper mapper;
    23. @DataSourceSwitch(DBTypeEnum.DS1)
    24. @Override
    25. public List getAll() {
    26. return mapper.selectList( null);
    27. }
    28. }
    
     
     
    1. package gsa.geographic.system.service.impl;
    2. import gsa.geographic.system.config.dataSource.DataSourceSwitch;
    3. import gsa.geographic.system.entity.TGoods;
    4. import gsa.geographic.system.dao.TGoodsMapper;
    5. import gsa.geographic.system.enumclass.DBTypeEnum;
    6. import gsa.geographic.system.service.TGoodsService;
    7. import com.baomidou.mybatisplus.service.impl.ServiceImpl;
    8. import org.springframework.beans.factory.annotation.Autowired;
    9. import org.springframework.stereotype.Service;
    10. import java.util.List;
    11. /**
    12. * <p>
    13. * 服务实现类
    14. * </p>
    15. *
    16. * @author df123
    17. * @since 2019-09-03
    18. */
    19. @Service
    20. public class TGoodsServiceImpl extends ServiceImpl<TGoodsMapper, TGoods> implements TGoodsService {
    21. @Autowired
    22. private TGoodsMapper goodsMapper;
    23. @DataSourceSwitch(DBTypeEnum.DS2)
    24. @Override
    25. public List getAll() {
    26. return goodsMapper.selectList( null);
    27. }
    28. }

    9 然后在写上测试用例。

    
     
     
    1. package gsa.geographic.system.service.impl;
    2. import gsa.geographic.system.service.TGoodsService;
    3. import gsa.geographic.system.service.TOrder0Service;
    4. import gsa.geographic.system.service.UserService;
    5. import org.junit.Test;
    6. import org.junit.runner.RunWith;
    7. import org.springframework.beans.factory.annotation.Autowired;
    8. import org.springframework.boot.test.context.SpringBootTest;
    9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    10. import java.util.List;
    11. import static org.junit.Assert.*;
    12. /**
    13. * @Author df
    14. * @Date 2019/9/3 16:40
    15. * @Version 1.0
    16. */
    17. @SpringBootTest
    18. @RunWith(SpringJUnit4ClassRunner.class)
    19. public class UserServiceImplTest {
    20. @Autowired
    21. private UserService userService;
    22. @Autowired
    23. private TOrder0Service tOrder0Service;
    24. @Autowired
    25. private TGoodsService goodsService;
    26. @Test
    27. public void getAll() {
    28. List list = userService.selectList( null);
    29. List list1=tOrder0Service.getAll();
    30. List list2=goodsService.getAll();
    31. System.out.println(list);
    32. }
    33. }

    10.控制台结果,也能看到确实使用了HikariCP的数据库连接池,这样就大公告成了

     

     

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值