Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。
它本身还自带一个监控平台,可以查看时时产生的sql、uri等监控数据,可以排查慢sql、慢请求,方便对sql和项目代码进行调优。
com.alibaba.druid.pool.DruidDataSource 基本配置参数如下
配置 | 缺省值 | 说明 |
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。? | |
jdbcUrl | 连接数据库的url,不同数据库不一样。例如:? | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter | |
driverClassName | 根据url自动识别 | 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下) |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 有两个含义:? | |
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun | |
minEvictableIdleTimeMillis | ||
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:? | |
proxyFilters | 类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
?数据库连接池是一种用于管理和复用数据库连接的技术。在应用程序与数据库之间建立连接是一项开销较大的操作,而连接池的目标是通过预先建立一组数据库连接,然后在应用程序需要时分配和复用这些连接,以减少连接建立和断开的开销,提高数据库访问的效率和性能。
?相关依赖
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.20</version>
</dependency>
<!--springboot整合druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://122.9.47.93:3306/
username:
password:
type: com.alibaba.druid.pool.DruidDataSource
package com.yanyu.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.support.jakarta.StatViewServlet;
import com.alibaba.druid.support.jakarta.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 org.springframework.context.annotation.Primary;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class MyDataSourceConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
@Primary
public DruidDataSource druid() throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://122.9.47.93:3306/2021213067");
dataSource.setName("");
dataSource.setPassword("");
dataSource.setInitialSize(7); // 初始化连接数
dataSource.setMinIdle(5); // 最小空闲连接数
dataSource.setMaxActive(22); // 最大活跃连接数
dataSource.setMaxWait(60000); // 获取连接的最大等待时间(毫秒)
dataSource.setTimeBetweenEvictionRunsMillis(60000); // 连接回收的时间间隔(毫秒)
dataSource.setMinEvictableIdleTimeMillis(300000); // 连接在池中保持空闲的最小时间(毫秒)
dataSource.setValidationQuery("SELECT 1 FROM DUAL"); // 验证连接是否有效的 SQL 语句
dataSource.setTestWhileIdle(true); // 当连接空闲时,是否进行有效性检测
dataSource.setTestOnBorrow(false); // 当从连接池借用连接时,是否进行有效性检测
dataSource.setTestOnReturn(false); // 当归还连接时,是否进行有效性检测
dataSource.setPoolPreparedStatements(true); // 是否使用预处理语句
//dataSource.setFilters("stat,wall,log4j"); // 配置监控统计拦截的 filters
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20); // 每个连接最多可以创建的预处理语句数量
dataSource.setUseGlobalDataSourceStat(true); // 是否使用全局数据源统计信息
dataSource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500"); // 连接属性配置
return dataSource;
}
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean();
registrationBean.setServlet(new StatViewServlet());
registrationBean.setUrlMappings(Arrays.asList("/druid/*"));
//设置初始化参数
Map<String,String> initMap = new HashMap<>();
initMap.put("loginUsername","admin");
initMap.put("loginPassword","123456");
initMap.put("allow","");
initMap.put("deny","192.168.2.110");
registrationBean.setInitParameters(initMap);
return registrationBean;
}
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new WebStatFilter());
registrationBean.setUrlPatterns(Arrays.asList("/*"));
//设置初始化参数
Map<String,String> initMap = new HashMap<>();
initMap.put("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
registrationBean.setInitParameters(initMap);
return registrationBean;
}
}
package com.yanyu.config;
import com.alibaba.druid.pool.DruidDataSource;
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 SpringbootDataJdbcApplicationTests { //DI注入数据源
@Autowired
DataSource dataSource;
@Test
public void contextLoads() throws SQLException { //看一下默认数据源
System.out.println(dataSource.getClass()); //获得连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
DruidDataSource druidDataSource = (DruidDataSource) dataSource;
System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
//关闭连接
connection.close();
}
}
Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。
//配置 Druid 监控管理后台的Servlet;
//内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
// 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet
// 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
Map<String, String> initParams = new HashMap<>();
//参数指定 loginUsername loginPassword 不可变
initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
initParams.put("loginPassword", "123456"); //后台管理界面的登录密码
//后台允许谁可以访问
//initParams.put("allow", "localhost"):表示只有本机可以访问
//initParams.put("allow", ""):为空或者为null时,表示允许所有访问
initParams.put("allow", "");
//deny:Druid 后台拒绝谁访问
//initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问
//设置初始化参数
bean.setInitParameters(initParams);
return bean;
}
配置完毕后,访问管理后台:?http://localhost:8080/druid/login.html
配置 Druid web 监控 filter 过滤器 – 过滤不需要监控的数据
//配置 Druid 监控 之 web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean webStatFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
//exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
bean.setInitParameters(initParams);
//"/*" 表示过滤所有请求
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
在数据源这里可以看到连接池的情况,包括配置文件中配置的连接数等参数,以及没有配置的一些默认参数。
?数据源的下半部分可以看到一些时时产生的数据,这些参数都附带了解释,一些重要的数据有:
?我们在配置文件中配置了慢sql的执行时间为3秒钟,这里会将超过3秒钟的sql标红,方便我们一眼就看到。可以从下图看到有两个mansql,并把sql显示了出来,我们可以针对性的进行sql优化。
??执行分布时间一共有8个档位,在上述数据源里已经看到了这8个档位的含义。
??可以看到最大并发数是40,这是因为在配置文件中配置了最大连接数为40,可以根据实际情况调整参数。
?点击左侧蓝色的sql,可以查看更详细的视图。
?记录配置文件中配置的黑、白名单的拦截信息,我这里没有配也没有数据。
可以看到整个项目的运行数据,主要记录的还是和数据库打交道的一些数据。
?有不少中间件都能实现对于URI的监控(sentinel、skywalking、zipkin等),德鲁伊侧重的是和数据库连接产生的数据,可以结合多个监控的数据一起参考。