一,了解Druid连接池
1,什么是Druid连接池
Druid是一个开源的数据库连接池,旨在为Java应用程序提供高性能、可扩展、易于管理的数据库连接服务。Druid通过优化数据库连接的使用方式,可以显著提高应用程序的性能和响应速度。其次,Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能。功能强大,能防SQL注入,内置Loging能诊断Hack应用行为。
2,Druid和Springboot默认连接池HikariCP对比
版本对比
HikariCP的版本较为多样,覆盖了不同的数据库和JDK版本。而Druid的版本则相对较少,但仍然支持多种数据库和JDK。在选择时,请确保您所使用的数据库和JDK版本与所选连接池版本兼容。
性能对比
在性能方面,两者都是很好的选择,但在大多数情况下,HikariCP的性能优于Druid。
HikariCP的优点如下:
1、快速启动,在启动时不需要初始化多余资源。
2、高效的对象封装:对象的封装采用了更少的内存,不会初始化多余资源,操作效率更高。
3、线程安全:线程调度的时候,不会受到阻塞的影响,增加了并发使用的效率。
Druid的优点如下:
1、大而全的功能:Druid支持的功能非常丰富,包括监控、SQL防火墙、SQL解析、SQL执行分析等等。
2、易于管理:Druid提供了非常详细的接口,可以帮助管理员实时监控系统状态,并提供了详细的日志。
3、使用方便:Druid的数据源扩展了JDBC的DataSource接口,通过简单配置即可实现数据库连接池的使用。
易用性对比
HikariCP提供了简洁的API和丰富的配置选项,使得配置和使用变得相对简单。而Druid的配置相对较为复杂,但提供了更多的监控和管理功能。在使用上,HikariCP可能更适合对性能和简洁性有较高要求的开发人员,而Druid可能更适合需要更强大监控和扩展功能的开发人员。
综上所述,HikariCP和Druid各有优劣,需要根据实际需求进行选择。如果需要频繁创建和关闭连接,对性能要求较高,可以选择HikariCP;如果需要长时间保持连接,对稳定性和监控功能要求较高,可以选择Druid。无论选择哪种数据库连接池,都需要对其进行充分的测试和监控,以确保其性能和稳定性满足应用程序的需求。同时,还需要关注其版本兼容性和易用性,以便在开发和维护过程中获得更好的体验。
3,Druid配置项说明
配置项名称 | 缺省值 | 说明 |
---|---|---|
name | DataSource-**** | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this) |
url | 连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | |
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 | 最大连接池数量 |
minIdle | 0 | 连接池最小空闲数量 |
maxWait | -1 | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | 10 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
maxPoolPreparedStatementPerConnectionSize | 10 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | null | 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。 |
validationQueryTimeout | -1 | 单位:秒,检测连接是否有效的超时时间,大于0才生效。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法 |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 60000 | 有两个含义: 1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
numTestsPerEvictionRun | 3 | 不再使用,已经彻底废弃,一个DruidDataSource只支持一个EvictionRun |
minEvictableIdleTimeMillis | 1800000 | 连接保持空闲而不被驱逐的最小时间 |
connectionInitSqls | [] | 数组方式定义物理连接初始化的时候执行的1到多条sql语句,比如连接MySQL数据库使用低版本驱动的情况下,想使用utf8mb4,则可以配置sql为: set NAMES 'utf8mb4' |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall | |
proxyFilters | 类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
二,SpringBoot3集成Druid
1,引入依赖
版本要和Springboot3兼容
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.38.0</version>
</dependency>
<!-- 如果你使用的是 Spring Boot 2.x 或更早版本,那么您应该使用 javax.servlet-api 而不是 jakarta.servlet-api -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
2,修改配置文件
spring:
datasource: # mysql 数据源配置
type: com.alibaba.druid.pool.DruidDataSource # 配置连接池类型为 druid
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/druid?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
druid:
# 初始化时建立物理连接的个数
initial-size: 5
# 连接池的最小空闲数量
min-idle: 5
# 连接池最大连接数量
max-active: 20
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-while-idle: true
# 既作为检测的间隔时间又作为testWhileIdel执行的依据
time-between-eviction-runs-millis: 60000
# 销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接(配置连接在池中的最小生存时间)
min-evictable-idle-time-millis: 30000
# 用来检测数据库连接是否有效的sql 必须是一个查询语句(oracle中为 select 1 from dual)
validation-query: select 1
# 申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
test-on-borrow: false
# 归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
test-on-return: false
# 是否缓存preparedStatement, 也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下建议关闭。
pool-prepared-statements: false
# 置监控统计拦截的filters,去掉后监控界面sql无法统计,stat: 监控统计、Slf4j:日志记录、waLL: 防御sqL注入
filters: stat,wall,slf4j
# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
max-pool-prepared-statement-per-connection-size: -1
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
web-stat-filter: # 监控web
enabled: true
# 添加过滤规则
url-pattern: /*
# 忽略过滤的格式
exclusions: /druid/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico
stat-view-servlet: # 配置监控页面
enabled: true
# 访问路径为/druid
url-pattern: /druid/*
# 是否能够重置数据
reset-enable: false
# 设置账号密码,默认为root
login-username: admin
login-password: admin
# IP白名单
allow: 127.0.0.1
# IP黑名单(共同存在时,deny优先于allow)
deny:
3,启动项目
出现如下日志表示使用druid连接池成功
4,访问监控页面
http://127.0.0.1:9090/druid
输入账号和密码
5,去除druid监控页面底部广告
编写配置类-DruidAdvertisingConfig,如果报错,可以将导入的类删了重新导入试试
package com.cms.config.druid;
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import jakarta.servlet.*;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* @author Hva
*/
@Configuration
@ConditionalOnWebApplication
@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
public class DruidAdvertisingConfig {
/**
* @Description: 除去页面底部的广告
*/
@Bean
public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
// 获取监控页面参数
DruidStatProperties.StatViewServlet druidConfig = properties.getStatViewServlet();
// 获取common.js位置
String pattern = druidConfig.getUrlPattern() != null ? druidConfig.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
final String filePath = "support/http/resources/js/common.js";
// 利用Filter进行过滤
Filter filter = new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
// 重置缓冲区,响应头不会重置
response.resetBuffer();
// 获取common文件内容
String text = Utils.readFromResource(filePath);
// 利用正则表达式删除<footer class="footer">中的<a>标签
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
text = text.replaceAll("powered.*?shrek.wang</a>", "");
// 去掉头部的菜单连接
text+="var t =null; $(function(){ t=setInterval(function(){$(\"a.brand\").hide()}, 10 ); setTimeout(function(){clearInterval(t)}, 2000 );})";
response.getWriter().write(text);
}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}
6,重新项目,访问druid
可以发现头部链接和底部广告都没有了