【SpringBoot 2.x】开发实战day11,整合springboot 与 Druid连接池(二),多数据源

在上一节记录了springboot 整合 Druid 单数据源的全过程,
传送门:【SpringBoot 2.x】开发实战day10,整合springboot 与 Druid连接池(一)
源码链接:SpringBoot-Modules-Study/tree/master/springboot-Day10


  对于开发人员来说,单一数据源满足不了项目需要,也就是多数据源很常见,那么这节记录多数据源配置和监控。

一、如何配置多数据源

  1. 引入Maven依赖
  2. 添加application.yml配置
  3. 手动创建config,手动加载DataSource、事务管理器,以及SQL工厂(这是与单数据源不同的地方,一定要手动配置,否则不生效

环境: JDK 8 、springBoot 2.1.8、Mybatis 2.1.0、Mysql、Druid

1、引入Maven依赖
<!-- Druid-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>
2、添加application.yml配置
server:
  port: 8888
debug: false
spring:
  # json 输出格式化与时间格式化
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss SSS
    time-zone: GMT+8
    serialization:
      indent-output: true
  mvc:
    date-format: yyyy-MM-dd
  # datasource
  datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      druid:
        driver-class-name: com.mysql.cj.jdbc.Driver
        # 主库数据源
        master:
          url: jdbc:mysql://localhost:3306/scott?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
          username: root
          password: 123456

        # 从库数据源
        slave:
          url: jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
          username: root
          password: 123456

        # Druid连接池配置
        # 数据库类型为mysql
        db-type: mysql
        # 启动时初始化5个连接
        initialSize: 5
        # 最小空闲连接5个
        min-idle: 5
        # 最大连接数量20
        max-active: 20
        # 获取连接等待时间60秒,超出报错
        max-wait: 60000
        # 每60秒执行一次连接回收器
        time-between-eviction-runs-millis: 60000
        # 5分钟内没有任何操作的空闲连接会被回收
        min-evictable-idle-time-millis: 300000
        # 验证连接有效性的SQL
        validation-query: select 'x'
        # 空闲时校验,建议开启
        test-while-idle: true
        # 使用中是否校验有效性,推荐关闭
        test-on-borrow: false
        # 归还连接时校验有效性,推荐关闭
        test-on-return: false
        # oracle 推荐使用
        pool-prepared-statements: false
        # 设置过滤器,stat用于接收状态,wall用于防止SQL注入
        filters: stat,wall
        # 支持合并多个DruidDataSource的监控数据
        use-global-data-source-stat: true
        # Druid监控配置
        # WebStatFilter配置
        web-stat-filter:
          # 是否启用StatFilter, 默认值true
          enabled: true
          # URL白名单
          url-pattern: /*
          # 过滤器排除掉的静态资源,yml配置需要用引号""
          exclusions:  "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
          # session 统计功能
          session-stat-enable: false
          # 最大session数
          session-stat-max-count: 1000
          # 你可以配置principalSessionName, 使得druid能够知道当前的session的用户是谁
          principal-session-name: administrator
          # druid能够知道当前的cookie的用户是谁
          principal-cookie-name: administrator
          # 配置profileEnable能够监控单个url调用的sql列表
          profile-enable: true

          # StatViewServlet配置 :展示Druid的统计信息, StatViewServlet的用途包括: 1.提供监控信息展示的html页面; 2.提供监控信息的JSON API
          stat-view-servlet:

          # 是否启用StatViewServlet, 默认值true
          enabled: true
          # 根据配置中的url-pattern来访问内置监控页面,内置监控页面的地址是{上下文}/druid
          url-pattern: /druid/*
          # 允许清空统计数据
          reset-enable: false
          # 配置登录用户名
		  login-username: administrator
          # 配置登录密码
		  login-password: 123456
          # 如果你需要做访问控制, 可以配置allow和deny这两个参数
          # deny优先于allow, 如果在deny列表中, 就算在allow列表中, 也会被拒绝. 如果allow没有配置或者为空, 则允许所有访问.
          allow: 127.0.0.1
          deny: 10.1.1.110

        filter:
          stat:
            # 是否启用statFilter
            enabled: true
            # 数据库类型
            db-type: mysql
            # 是否开启慢sql日志,针对执行效率低的SQL记录日志
            log-slow-sql: true
            # 设置超过指定时间为慢SQL
            slow-sql-millis: 2000

          # WallFilter配置
          wall:
            # 是否启用WallFilter, 默认值true
            enabled: true
            # 数据库类型
            db-type: mysql
            config:
              delete-allow: false
              drop-table-allow: false
              alter-table-allow: false
              truncate-allow: false
              # 是否允许非以上基本语句的其他语句, 缺省关闭, 通过这个选项就能够屏蔽DDL
              none-base-statement-allow: false
              # 检查UPDATE语句是否无where条件, 这是有风险的, 但不是SQL注入类型的风险
              update-where-none-check: true
              # SELECT ... INTO OUTFILE 是否允许, 缺省是禁止的
              select-into-outfile-allow: false
              # 是否允许调用Connection.getMetadata方法, 这个方法调用会暴露数据库的表信息
              metadata-allow: true
            # 对被认为是攻击的SQL进行LOG.error输出
            log-violation: true
            # 对被认为是攻击的SQL抛出SQLExcepton
            throw-exception: true


# mybatis
mybatis:
  # 核心配置文件,指定的是mybatis-config.xml
  config-location: classpath:/mybatis/mybatis-config.xml
  # 指定mapper映射文件,全注解方式不需要
  mapper-locations: classpath:/mybatis/mapper/*Mapper.xml

# 打印sql
logging:
  level:
     cn.gcheng.springboot.mapper : debug

这里需要注意两个配置:
① 配置两个数据库,主从库的配置信息

driver-class-name: com.mysql.cj.jdbc.Driver
# 主库数据源
master:
  url: jdbc:mysql://localhost:3306/scott?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
  username: root
  password: 123456

# 从库数据源
slave:
  url: jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
  username: root
  password: 123456

② 支持多个数据源的监控数据

# 支持合并多个DruidDataSource的监控数据
use-global-data-source-stat: true

3、创建配置类,手动创建Bean

① 创建获取application.yml配置文件的常量基类
DataSourceConfig.java

public class DataSourceConfig {

    /**
     * 表示mapper.xml 映射地址,这一在配置文件中配置不同的位置
     */
    @Value("${mybatis.mapper-locations}")
    protected final String MAPPER_LOCAL = null;

    @Value("${spring.datasource.druid.db-type}")
    protected String dbType;

    @Value("${spring.datasource.druid.initialSize}")
    protected int initialSize;

    @Value("${spring.datasource.druid.min-idle}")
    protected int minIdle;

    @Value("${spring.datasource.druid.max-active}")
    protected int maxActive;

    @Value("${spring.datasource.druid.max-wait}")
    protected int maxWait;

    @Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
    protected int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.druid.min-evictable-idle-time-millis}")
    protected int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.validation-query}")
    protected String validationQuery;

    @Value("${spring.datasource.druid.test-while-idle}")
    protected boolean testWhileIdle;

    @Value("${spring.datasource.druid.test-on-borrow}")
    protected boolean testOnBorrow;

    @Value("${spring.datasource.druid.test-on-return}")
    protected boolean testOnReturn;

    @Value("${spring.datasource.druid.pool-prepared-statements}")
    protected boolean poolPreparedStatements;

    @Value("${spring.datasource.druid.filters}")
    protected String filters;

    @Value("${spring.datasource.druid.use-global-data-source-stat}")
    protected boolean useGlobalDataSourceStat;

    @Value("${spring.datasource.druid.driver-class-name}")
    protected String driverClassName;

    protected DruidDataSource getDataSourceProperties() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driverClassName);
        ds.setDbType(dbType);
        ds.setInitialSize(initialSize);
        ds.setMinIdle(minIdle);
        ds.setMaxActive(maxActive);
        ds.setMaxWait(maxWait);
        ds.setTimeBetweenConnectErrorMillis(timeBetweenEvictionRunsMillis);
        ds.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        ds.setValidationQuery(validationQuery);
        ds.setTestWhileIdle(testWhileIdle);
        ds.setTestOnBorrow(testOnBorrow);
        ds.setTestOnReturn(testOnReturn);
        ds.setPoolPreparedStatements(poolPreparedStatements);
        ds.setUseGlobalDataSourceStat(useGlobalDataSourceStat);

        return ds;
    }
}

② master 主库数据源配置

@Configuration
// 指定扫描的mapper
@MapperScan(basePackages = {"cn.gcheng.springboot.mapper.master"}, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourcesConfig extends DataSourceConfig{

    /**
     * 获取配置文件中数据库配置属性, 属性常量配置在父类中
     */
    @Value("${spring.datasource.druid.master.url}")
    private String url;

    @Value("${spring.datasource.druid.master.username}")
    private String username;

    @Value("${spring.datasource.druid.master.password}")
    private String password;


    /**
     * 注册 master 数据源, @Primary标志这个 Bean 如果在多个同类 Bean 候选时,该 Bean 优先被考虑。
     * @return
     */
    @Primary
    @Bean("masterDataSource")
    public DataSource masterDataSourceBean() {
        DruidDataSource ds = getDataSourceProperties();
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        try {
            ds.setFilters(filters);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return ds;
    }

    /**
     * 注册 master 事务管理器
     * 用来开启开启主库的事务@Transactional(rollbackFor = Exception.class,value = "masterTransactionManager") value 可以省略
     * @return
     */
    @Primary
    @Bean(name = "masterTransactionManager")
    public DataSourceTransactionManager masterTransactionManager() {
        return new DataSourceTransactionManager(masterDataSourceBean());
    }

    @Primary
    @Bean(name = "masterSqlSessionFactory")
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCAL));
        return sessionFactoryBean.getObject();
    }

}

说明注意事项:
   i:@Primary: 多数据源配置的时候注意,必须要有一个主数据源, 用 @Primary 标志该 Bean。标志这个 Bean 如果在多个同类 Bean 候选时,该 Bean优先被考虑。
   ii: dataSource.setFilters(filters): 这个是用来配置 druid 监控sql语句的, 如果你有两个数据源这个配置哪个数据源就监控哪个数据源的sql,同时配置那就都监控。
  iii: 能够做到多个数据源的关键 就是每个数据源所扫描的mapper包不一样,谁扫描到哪个mapper那么该mapper就用哪个数据源,同时都扫到了呢,那当然就得用主数据源咯,也就是添加@Primary 的数据源。

③ 配置从库数据源:

@Configuration
// 指定扫描的mapper路径
@MapperScan(basePackages = {"cn.gcheng.springboot.mapper.slave"}, sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourcesConfig extends DataSourceConfig{

    /**
     * 获取配置文件中数据库配置属性, 属性常量配置在父类中
     */
    @Value("${spring.datasource.druid.slave.url}")
    private String url;

    @Value("${spring.datasource.druid.slave.username}")
    private String username;

    @Value("${spring.datasource.druid.slave.password}")
    private String password;

    /**
     * 注册 slave 数据源
     * @return
     */
    @Bean("slaveDataSource")
    public DataSource slaveDataSourceBean() {
        DruidDataSource ds = getDataSourceProperties();
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        try {
            ds.setFilters(filters);
        } catch (SQLException e) {
            e.printStackTrace();

        }

        return ds;
    }

    /**
     * 注册 slave 事务管理器
     * 用来开启开启主库的事务@Transactional(rollbackFor = Exception.class,value = "slaveTransactionManager"),不同的是value 不可以省略
     * @return
     */
    @Bean(name = "slaveTransactionManager")
    public DataSourceTransactionManager slaveTransactionManager() {
        return new DataSourceTransactionManager(slaveDataSourceBean());
    }

    @Bean(name = "slaveSqlSessionFactory")
    public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCAL));
        return sessionFactoryBean.getObject();
    }
}

   i: 发现从数据源所扫描的mapper和主是完全不一样的,说明每个数据源负责自己的mapper
   ii: 从数据源是没有加@Primary
   iii: 这里也添加了dataSource.setFilters(filters),说明从数据源也需要监听sql语句。


二、简单测试和查看监控情况

   启动项目,访问配置的 http://localhost:8888/druid 。可以打开,监控有数据,URL访问也可以检测到,说明没问题。
SQL监控:
在这里插入图片描述
数据源监控:
   这里要说明一点,你启动项目后查看数据源监控可能是这样的,这不是配置错误。
在这里插入图片描述
需要访问后台,它才加载数据源监控。
主数据源
在这里插入图片描述
从数据源
在这里插入图片描述
URI监控:
在这里插入图片描述


三、参考文档

https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
https://www.cnblogs.com/kingsonfu/p/10427408.html
https://www.cnblogs.com/qdhxhz/p/10192041.html


源码地址

SpringBoot-Modules-Study/tree/master/springboot-Day11

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值