为什么要写本文?

官方文档给的不够详细,下面是一个能即读即用的版本
主要也方便自己以后参考代码,不再重复查找
本文使用的springboot版本:2.2.6.RELEASE

添加依赖

查看一下最新版本的插件:https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter

druid插件的最新版也要看看:https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter
不过这里,还是建议看mybatis plus所支持的druid版本。

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <optional>true</optional>
  5. </dependency>
  6. <!--@DS注解需要的依赖-->
  7. <dependency>
  8. <groupId>com.baomidou</groupId>
  9. <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  10. <version>3.0.0</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.baomidou</groupId>
  14. <artifactId>mybatis-plus-boot-starter</artifactId>
  15. <version>3.3.1</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>com.alibaba</groupId>
  19. <artifactId>druid-spring-boot-starter</artifactId>
  20. <version>1.1.21</version>
  21. </dependency>
  22. <dependency>
  23. <groupId>mysql</groupId>
  24. <artifactId>mysql-connector-java</artifactId>
  25. <scope>runtime</scope>
  26. </dependency>

配置文件

首先要移除Druid自动配置类:

  1. @SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)

某些springBoot的版本上面可能无法排除可用以下方式排除。

  1. spring:
  2. autoconfigure:
  3. exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

原因:DruidDataSourceAutoConfigure会注入一个DataSourceWrapper,其会在原生的spring.datasource下找url,username,password等。而我们动态数据源的配置路径是变化的。

然后下面是非常简单的一个druid配置(附录有完整配置):

  1. spring:
  2. datasource:
  3. dynamic:
  4. # 默认源
  5. primary: druid-admin
  6. druid:
  7. #初始化大小,最小,最大
  8. initial-size: 5
  9. min-idle: 5
  10. max-active: 20
  11. datasource:
  12. # 数据源1
  13. druid-admin:
  14. url: jdbc:mysql://IP:3306/db_admin?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  15. username: xxx
  16. password: xxx
  17. driver-class-name: com.mysql.cj.jdbc.Driver
  18. # 数据源2
  19. druid-web:
  20. url: jdbc:mysql://IP:3306/db_web?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  21. username: xxx
  22. password: xxx
  23. driver-class-name: com.mysql.cj.jdbc.Driver

代码

因为要用分页查询测试,所以加上分页插件

  1. /**
  2. * 分页插件,解决分页时total=0问题
  3. */
  4. @Bean
  5. public PaginationInterceptor paginationInterceptor() {
  6. return new PaginationInterceptor();
  7. }

准备实体类

  1. import com.baomidou.mybatisplus.annotation.IdType;
  2. import com.baomidou.mybatisplus.annotation.TableField;
  3. import com.baomidou.mybatisplus.annotation.TableId;
  4. import com.baomidou.mybatisplus.annotation.TableName;
  5. import lombok.Data;
  6. @Data
  7. @TableName("t_user")
  8. public class User {
  9. @TableId(type = IdType.AUTO)
  10. private Integer id;
  11. @TableField(value = "user_name")
  12. private String username;
  13. private String password;
  14. private String email;
  15. }
  16. @Data
  17. @TableName("role")
  18. public class Role {
  19. @TableId(type = IdType.AUTO)
  20. private Integer id;
  21. private String name;
  22. }

准备mapper

只需要继承BaseMapper得到常用的CRUD接口方法即可,再加上@Mapper注解标识

  1. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  2. import com.jimo.mybatisplusdruiddemo.model.User;
  3. import org.apache.ibatis.annotations.Mapper;
  4. @Mapper
  5. public interface UserMapper extends BaseMapper {
  6. }
  7. @Mapper
  8. public interface RoleMapper extends BaseMapper {
  9. }

写service层

只需继承ServiceImpl就好。

这里的@DS注解就是选择数据源的,名字与配置里的对应

  1. import com.baomidou.dynamic.datasource.annotation.DS;
  2. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  3. import com.jimo.mybatisplusdruiddemo.mapper.UserMapper;
  4. import com.jimo.mybatisplusdruiddemo.model.User;
  5. import org.springframework.stereotype.Service;
  6. @Service
  7. @DS("druid-web")
  8. public class UserService extends ServiceImpl<UserMapper, User> {
  9. }
  10. /**
  11. • 因为默认就是druid-admin库,所以,可以省略,加上也没关系
  12. */
  13. @Service
  14. //@DS("druid-admin")
  15. public class RoleService extends ServiceImpl<RoleMapper, Role> {
  16. }

测试

测试类非常简单,执行一个分页查询:

@SpringBootTest
class MybatisPlusDruidDemoApplicationTests {

  1. @Autowired
  2. private UserService userService;
  3. @Autowired
  4. private RoleService roleService;
  5. @Test
  6. void testUserService() {
  7. final int size = 10;
  8. final Page<User> page = userService.page(new Page<>(1, size));
  9. assertEquals(size, page.getRecords().size());
  10. assertTrue(page.getTotal() >= size);
  11. }
  12. @Test
  13. void testRoleService() {
  14. final int size = 1;
  15. final Page<Role> page = roleService.page(new Page<>(1, size));
  16. assertEquals(size, page.getRecords().size());
  17. assertTrue(page.getTotal() >= size);
  18. }

可以看到日志里数据库的初始化和销毁:

  1. 2020-04-01 10:34:20.661 INFO 15600 --- [ main] j.m.MybatisPlusDruidDemoApplicationTests : No active profile set, falling back to default profiles: default
  2. 2020-04-01 10:34:22.805 INFO 15600 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1,druid-admin} inited
  3. 2020-04-01 10:34:23.118 INFO 15600 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-2,druid-web} inited
  4. 2020-04-01 10:34:23.118 INFO 15600 --- [ main] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource - load a datasource named [druid-admin] success
  5. 2020-04-01 10:34:23.119 INFO 15600 --- [ main] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource - load a datasource named [druid-web] success
  6. 2020-04-01 10:34:23.119 INFO 15600 --- [ main] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource initial loaded [2] datasource,primary datasource named [druid-admin]
  7. | |. __ | _
  8. | | |/|)(| | |\ |)|||\
  9. / |
  10. 3.3.1
  11. 2020-04-01 10:34:24.379 INFO 15600 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
  12. 2020-04-01 10:34:24.888 INFO 15600 --- [ main] j.m.MybatisPlusDruidDemoApplicationTests : Started MybatisPlusDruidDemoApplicationTests in 4.695 seconds (JVM running for 6.375)
  13. ...
  14. 2020-04-01 10:34:56.112 INFO 15600 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
  15. 2020-04-01 10:34:56.113 INFO 15600 --- [extShutdownHook] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource start closing ....
  16. 2020-04-01 10:34:56.116 INFO 15600 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ...
  17. 2020-04-01 10:34:56.126 INFO 15600 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed
  18. 2020-04-01 10:34:56.126 INFO 15600 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closing ...
  19. 2020-04-01 10:34:56.130 INFO 15600 --- [extShutdownHook] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closed
  20. 2020-04-01 10:34:56.130 INFO 15600 --- [extShutdownHook] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource all closed success,bye

总结

重点强调

@DS(“druid-web”)注解用来选择数据源,是可以用在mapper层的

  1. @Mapper
  2. @DS("druid-web")
  3. public interface UserMapper extends BaseMapper {
  4. }

就像有时候偷懒,不想写service层,也可以在mapper就实现多数据源切换:

  1. @Autowired
  2. private UserMapper userMapper;
  3. @Test
  4. void testUserMapper() {
  5. final int size = 10;
  6. final Page<User> page = userMapper.selectPage(new Page<>(1, size), null);
  7. assertEquals(size, page.getRecords().size());
  8. assertTrue(page.getTotal() >= size);
  9. }

附录

druid的完整配置:

  1. spring:
  2. datasource:
  3. dynamic:
  4. primary: druid-admin
  5. druid:
  6. #初始化大小,最小,最大
  7. initial-size: 5
  8. min-idle: 5
  9. max-active: 20
  10. #配置获取连接等待超时的时间
  11. max-wait: 60000
  12. #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  13. time-between-eviction-runs-millis: 60000
  14. #配置一个连接在池中最小生存的时间,单位是毫秒
  15. min-evictable-idle-time-millis: 300000
  16. validation-query: SELECT 1 FROM DUAL
  17. test-while-idle: true
  18. test-on-borrow: false
  19. test-on-return: false
  20. #打开PSCache,并且指定每个连接上PSCache的大小
  21. pool-prepared-statements: true
  22. max-pool-prepared-statement-per-connection-size: 20
  23. #配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
  24. filters: stat,wall # 注意这个值和druid原生不一致,默认启动了stat,wall
  25. filter:
  26. log4j:
  27. enabled: true
  28. wall:
  29. config:
  30. # 允许多个语句一起执行
  31. multi-statement-allow: true
  32. enabled: true
  33. db-type: mysql
  34. stat:
  35. enabled: true
  36. db-type: mysql
  37. datasource:
  38. # 数据源1
  39. druid-admin:
  40. url: jdbc:mysql://IP:3306/db_admin?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  41. username: xxx
  42. password: xxx
  43. driver-class-name: com.mysql.cj.jdbc.Driver
  44. # 数据源2
  45. druid-web:
  46. url: jdbc:mysql://IP:3306/db_web?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  47. username: xxx
  48. password: xxx
  49. driver-class-name: com.mysql.cj.jdbc.Driver

参考

https://mybatis.plus/guide/dynamic-datasource.html
https://github.com/baomidou/dynamic-datasource-spring-boot-starter/wiki/Integration-With-Druid