SpringBoot基础学习之整合Druid数据源

前言

小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个SpringBoot基础学习系列用来记录我学习SpringBoot框架基础知识的全过程 (这个系列是参照B站狂神的SpringBoot最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将会以一天一更的速度更新这个系列,还没有学习SpringBoot的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。
最后,希望能够和大家一同进步吧!加油吧!少年们!

废话不多说,让我们开始今天的学习内容吧,由于今天我们来到了SpringBoot基础学习的第七站:整合Druid数据源

6.2 整合Druid数据源

6.2.1 Druid数据源介绍

1.Druid数据源简介

  • Druid是阿里巴巴开发的一个开源的数据库连接池,结合了C3P0、DBCP和PROXOOL等DB池的优点,同时加入了日志监控
  • Druid可以很好的监控DB池连接和SQL的执行情况,天生是针对监控而生的DB连接池
  • Spring Boot 2.0 以上默认使用Hikari数据源,可以说Hikari与Druid都是当前Java Web上较为优秀的数据源,

2.Druid数据源常用配置参数

我们来重点介绍Spring Boot 如何集成Druid数据源,如何实现数据库监控,以下是Druid数据源的常用配置参数表:

配置 缺省值 说明
name (数据源名称) 配置这个属性的意义在于,如果存在多个数据源,监控时可以通过名字来区分开;如果没有配置,将会生成一个名字,格式为:“DataSource-” + System.identifyHashCode(this)
url (url连接) 连接数据库的url,不同数据库不一样;例如,mysql:jdbc:mysql://localhost:3306/druid2;orcale:jdbc:orcale:thin:@localhost:1521:ocnauto
username (用户名) 连接数据库的用户名
password (密码) 连接数据库的密码
driverClassName (驱动名) 根据url自动识别 这一项可配可不配,如果不配置Druid会根据url识别数据库类型,然后选择相应的DriverClassName
initialSize (初始化物理连接个数) 0 初始化时建立物理连接的个数,初始化发生在显式调用init方法,或者第一次getConnection时
maxActive (最大连接池数) 8 最大连接池数量
maxIdle (最大空闲数) 8 已经不再使用了,配置了也没效果
mindle 最小连接池数量
maxWait (最大等待时间) 获取连接时最大等待时间,单位毫秒;配置了maxWait之后,缺省启用公平锁,并发效率会有所下降;如果需要可以通过配置useUnicodeLock属性为true,使用非公平锁
poolPreparedStatements (预编译池) false 是否缓存preparedStatement,也就是PSCache;PSCache对支持游标的数据库性能提升巨大,比如说Oracle;在MySQL 5.5以下的版本中没有PSCache功能,建议关闭掉;MySQL 5.5以上版本有PSCache,建议开启
maxOpenPreparedStatements (开放的最大预编译语句数) -1 要启动PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true;在Druid中,不会存在Orcale下PSCache占内存过多的问题,可以把这个数值配置再大一些,比如说100
validationQueryfont> (查询是否生效) 用来检测连接是否有效的SQL,要求是一个查询语句;如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用;在MySQL中通知Select ‘X’,在Oracle中通常为Select 1 from dual
testOnBorrow (检测引入查询语句的连接是否有效) false 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testOnReturn (测试归还连接是否有效) false 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testWhiteIdle (检测空闲连接时间是否大于回收和运行间隔) false 建议配置为true,不影响性能,并且保证安全性;申请连接时检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validatioQuery检测连接是否有效
timeBetweenEvictionRunsMillis (回收和运行时间间隔) 有两个含义:Destroy线程检测连接的间隔时间; testWhiteIdle的判断依据
numTestsPerEvictionRun (每个回收和运行的测试数量) 不再使用,一个DruidDatsSource只支持一个EvictionRun
minEvictableTimeMillis (最小回收时间) Destroy线程,如果检测到当前连接的最后活跃时间和当前时间大于minEvictableTimeMillis,则关闭当前连接
connectionInitSqls (连接初始化SQL) 物理连接初始化时执行的SQL
exceptionSorter (异常分类机) 根据dbType (数据库类型)自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接
filters(过滤器) 属性类型是字符串,通过别名的方式配置扩展插件;常用的插件有:监控统计的filter:stat;日志用的filter:log4j;防御SQL注入的filter:wall
proxyFilters (动态过滤器) 类型是List<com.alibaba.druid.filter.Filter>,如果同时配置filters和ProxyFilters,是组合关系,并非替换关系

6.2.2 引入Druid数据源

1.导入资源依赖和修改配置文件

1-1 导Druid的资源依赖
  • 在pom.xml配置文件中导入Druid和log4j的资源依赖
<!-- Druid数据源资源依赖 -->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.12</version>
</dependency>
<!-- log4j资源依赖 -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  • 在外部资源中查看druid的相关资源依赖
    SpringBoot基础学习之整合Druid数据源
    SpringBoot基础学习之整合Druid数据源
1-2 修改核心配置文件
# 设置服务器端口号
server:
  port: 8888
# 设置数据库驱动
spring:
  datasource:
    username: root
    password: 123456
    # MySQL8.0版本的url链接格式
    #    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true
    # com.mysql.cj.jdbc.Driver是8.0版本以上的数据库
    # driver-class-name: com.mysql.cj.jdbc.Driver
    # com.mysql.jdbc.Driver是8.0以下版本的数据库
    driver-class-name: com.mysql.jdbc.Driver
    # 使用Druid的数据源
    type: com.alibaba.druid.pool.DruidDataSource
    # Spring Boot 默认是不注入这些属性值的,因此需要自己来配置
    # 设置Druid数据源的基本配置
    # 初始化时的物理连接个数:初始化发生在显式调用init方法或者第一次getConnection时
    initialSize: 5
    # 最小连接池数量
    minIdle: 5
    # 最大连接池数量
    maxActive: 20
    # 获取连接的最大等待时间,时间单位是毫秒
    maxWait: 60000
    # 运行和回收的间隔时间:即销毁线程检测连接的间隔时间
    timeBetweenEvictionRunsMillis: 300000
    # 最小回收时间:如果检测到当前连接的最后活跃时间和当前时间大于最小回收时间,则关闭当前连接
    minEvictableIdleTimeMillis: 300000
    # 判断连接到的查询语句是否有效
    validationQuery: Select 1 from dual
    # 检测空闲连接时间:建议设置为true,申请连接检测,如果空闲时间大于回收运行间隔时间,执行检测连接到的查询语句是否生效
    testWhiteIdle: true
    # 检测引入的查询语言的连接是否生效:此配置会降低性能,默认值为false
    testOnBorrow: false
    # 检测归还连接时执行生效查询语句是否有效:此配置会降低性能
    testOnReturn: false
    # 是否缓存预编译语句池:即使用PSCache,默认值为false,MySQL5.5以上版本有PSCache,建议开启
    poolPreparedStatements: true

    # 配置监控拦截的filters:监控统计-stat;日志记录-log4j;防御SQL注入:wall
    # 如果运行时报错-java.lang.ClassNotFoundException:org.apache,log4j.Priority
    # 则导入log4j依赖即可,Maven仓库地址:https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,log4j,wall
    # 设置每个连接的最大池预编译语句大小
    maxPoolPreparedStatementPerConnectionSize: 20
    # 设置使用全局的数据源的监控统计拦截器stat
    useGlobalDataSourceStat: true
    # 设置连接属性:监控统计拦截器stat的mergeSql(合并SQL)属性为true,即此配置生效;慢SQL时间为0.5秒
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

2.查看修改后的数据源

2-1 启动测试类
package com.kuang;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@SpringBootTest
class Springboot04DataApplicationTests {
    
    // 使用@Autowired注解将DataSource自动装配到Spring容器中
    @Autowired
    DataSource dataSource; // 数据源
    
    @Test
    void contextLoads() throws SQLException {
        // 查看默认的数据源:class com.zaxxer.hikari.HikariDataSource,相当于DBCP等数据源
        System.out.println(dataSource.getClass());
        // 获取数据库连接
        Connection connection  = dataSource.getConnection();
        // 打印connection连接信息
        System.out.println(connection);
        // xxx Template:SpringBoot已经配置好模板bean,拿来即用 CRUD
        // 关闭数据库连接
        connection.close();
    }
    
}
2-2 测试结果

SpringBoot基础学习之整合Druid数据源

6.2.3 自定义数据源

1.查看动态注册器Bean源码

  • 在IDEA中搜索DynamicRegistrationBean类,查看其如何实现动态注册
// 动态注册器Bean
public abstract class DynamicRegistrationBean<D extends Dynamic> extends RegistrationBean {
    
    // 通过日志工厂获取Log日志信息
    private static final Log logger = LogFactory.getLog(RegistrationBean.class);
    
    private String name; // 名字
    
    private boolean asyncSupported = true; // 开启异步支持 
    
    // 通过创建链表HashMap对象,使用Map键值对形式来存储初始化参数
    private Map<String, String> initParameters = new LinkedHashMap();
    
    // 动态注册器Bean的无参构造器
    public DynamicRegistrationBean() {
    }
    
    // 设置名字
    public void setName(String name) {
        // 断言名字不能为空
        Assert.hasLength(name, "Name must not be empty");
        this.name = name;
    }
    
    // 设置异步支持
    public void setAsyncSupported(boolean asyncSupported) {
        
        this.asyncSupported = asyncSupported;
    }
    // 获取异步支持
    public boolean isAsyncSupported() {
        return this.asyncSupported;
    }
    
    // 设置初始化参数方法
    public void setInitParameters(Map<String, String> initParameters) {
        // 断言初始化参数是否为空
        Assert.notNull(initParameters, "InitParameters must not be null");
        // 如果为空,通过创建链式HashMap对象来初始化参数
        this.initParameters = new LinkedHashMap(initParameters);
    }
    
    //...(省略后面部分代码)...
}

2.编写自定义DruidConfig

package com.kuang.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

// 将DruidConfig注册为配置类
@Configuration
public class DruidConfig {

    // 将Druid数据源与spring的datasource配置文件关联
    @ConfigurationProperties(prefix = "spring.datasource")
    // 将Druid数据源当做组件,注册到Spring容器中
    @Bean
    // 获取DruidDataSource的方法
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    /** 
     * 后台监控:web.xml和ServletRegistrationBean
     * 因为SpringBoot内置了Servlet容器,所以没有web.xml,替代方法:使用ServletRegistrationBean
     */
    // 将后台监控statViewServlet,当做组件注册到Spring容器中
    @Bean
    public ServletRegistrationBean statViewServlet() {
        // 创建Servlet注册Bean:有两个参数:第一个是监控视图过滤器,第二个是配置一个访问页面
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(),"/druid/*");
        // 后台需要有人登录,账号密码配置
        // 创建HashMap集合,存放账户密码键值对
        HashMap<String, String>initParameters = new HashMap<>();
        // 增加配置
        // 登录的key是固定的:loginUsername和loginPassword
        initParameters.put("loginUsername","admin");
        initParameters.put("loginPassword","123456");
        // 允许谁可以访问
        initParameters.put("allow","");
        // 禁止谁能访问
//        initParameters.put("zhangsan", "192.168.1.2");
       // 设置初始化参数
        bean.setInitParameters(initParameters);
        // 返回Servlet注册Bean
        return bean;
    }

    // Web后台监控过滤器
    public FilterRegistrationBean webStatFilter() {
        // 创建过滤器注册Bean
        FilterRegistrationBean bean = new FilterRegistrationBean();
        // 设置过滤器:通过Web后台监控过滤器
        bean.setFilter(new WebStatFilter());
        // 可以过滤哪些请求
        // 创建HashMap集合:存放不过滤信息的键值对
        Map<String, String> initParameters = new HashMap<>();
        // 设置不进行过滤的信息
        initParameters.put("exclusions", "*.js,*.css,/druid/*");
        // 设置初始化参数
        bean.setInitParameters(initParameters);
        // 返回过滤器注册Bean
        return bean;
    }
    
}

6.2.4 Druid登录验证和后台SQL监控

1.Druid登录验证测试

  • 启动SpringBoot项目后,在地址链接后面加上/druid/login.html,然后就可以进入到登录界面了

SpringBoot基础学习之整合Druid数据源

  • 输入在DruidConfig配置类中设置好的管理员用户名和密码,通过验证后进入到监控后台

SpringBoot基础学习之整合Druid数据源

  • 成功进入到Druid监控后台首页,可以看到一些相关信息,例如数据库数据源驱动,以及Java的JDK版本

SpringBoot基础学习之整合Druid数据源

2.后台SQL监控测试

2-1 访问用户列表和查看SQL监控
  • 编写JDBCController实现查询用户
package com.kuang.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

// 使用@RestController注解,实现Controller接口并且返回值为字符串
@RestController
public class JdbcController {
    
    // 使用@Autowired注解,自动装配JdbcTemplate(JDBC模板)类到Spring容器中
    @Autowired
    JdbcTemplate jdbcTemplate;

    /** 
     * 查询用户列表信息
     * 没有实体类,数据库中的内容,怎么获取?可以使用万能的Map
     */
    /**
     * 使用@RequestMapping注解,设置请求映射路径
     * 真实访问路径:http://localhost:8080/getList
     */
    @RequestMapping("/getList")
    public List<Map<String, Object>> getUserList() {
        // 封装SQL查询语句到字符串sql中去
        String sql = "select * from user";
        // 调用JDBC模板引擎的queryForList来获取用户数组集合信息
        List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);
        // 返回到用户集合
        return list_maps;
    }
    
}
  • 测试结果

SpringBoot基础学习之整合Druid数据源

结果查询用户列表信息成功!

  • 查看后台SQL监控

SpringBoot基础学习之整合Druid数据源

结果SQL监控记录了执行查询SQL语句的操作!

2-2 删除用户信息
  • 编写JDBCController实现删除用户
package com.kuang.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
//使用@RestController注解,实现Controller接口并且返回值为字符串
@RestController
public class JdbcController {
    //使用@Autowired注解,自动装配JdbcTemplate(JDBC模板)类到Spring容器中
    @Autowired
    JdbcTemplate jdbcTemplate;

    //修改用户信息
    //真实访问路径:http://localhost:8080/updateUser
    //使用@RequestMapping注解,设置请求映射路径
    @RequestMapping("/deleteUser/{userId}")
    public String delteUser(@PathVariable("userId") int id) {
        //封装SQL修改语句到字符串sql中去
        String sql = "delete from mybatis.user where id=?";
        //JDBC模板调用update方法进行修改数据
        jdbcTemplate.update(sql,id);
        //返回一个"Update-OK"
        return "Delete-OK";
    }
}
  • 测试结果

SpringBoot基础学习之整合Druid数据源

结果删除指定用户信息成功!

2-3 查看Druid的后台SQL监控

SpringBoot基础学习之整合Druid数据源

结果SQL监控记录了执行删除SQL语句操作!

结论

通过上面的测试,我们体会到了Druid数据源强大的SQL监控功能,不仅能够监测SQL语句的执行,包括执行次数、执行时间和更新行数、读取行数,以及最大并发操作和执行时间分布

3.Druid的SQL防火墙

  • 当然,Druid除了强大的SQL监控功能,同时还具有SQL防火墙这一功能,能够统计各种SQL执行次数和函数的调用,以及统计SQL防御的白名单和黑名单,可见其功能十分强大!

SpringBoot基础学习之整合Druid数据源


好了,今天的有关 SpringBoot基础学习之整合Druid数据源 的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!


参考视频链接:https://www.bilibili.com/video/BV1PE411i7CV(【狂神说Java】SpringBoot最新教程IDEA版通俗易懂)

上一篇:SpringBoot整个Druid


下一篇:springboot配置Oracle数据库双数据源