0


SpringBoot实战(二十)集成Druid连接池

目录

一、简介

1.定义

Druid数据库连接池

:是一个 Java 语言编写的高性能、高可用性的开源数据库连接池组件,有阿里巴巴开发和维护。它提供了一种可靠的、可管理的、高性能的数据库连接池解决方案,可以在 Java 应用程序中管理和复用数据库连接。

2.特点

以下是Druid连接池组件的特点:

  1. 基于开放标准:Druid连接池 完全遵循 Java 数据库连接标准(JDBC),可以与任何标准的 JDBC 驱动程序一起使用。
  2. 高性能:Druid连接池 采用了一系列优化策略和技术,包括连接池预热、连接池缓存、合理的连接分配等,以提供高并发、低延迟的数据库连接服务。
  3. 监控和统计:Druid连接池 提供了一套完善的监控和统计功能,可以实时监控连接池的使用情况、性能指标以及 SQL 执行情况,方便开发人员进行系统调优和性能优化。
  4. 安全可靠:Druid连接池 通过内置的防火墙和黑名单机制,可以预防恶意攻击和 SQL 注入等安全威胁,保证系统的安全可靠性。
  5. 扩展性强:Druid连接池 支持定制化扩展,可以根据具体业务场景和需求进行灵活的配置和编程。

3.连接池配置说明

配置缺省值说明

name

配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开。
如果没有配置,将会生成一个名字,格式是:“DataSource-” + System.identityHashCode(this)。

jdbcUrl

连接数据库的url,不同数据库不一样。例如:
mysql:jdbc:mysql://127.0.0.1:3306/mydb
oracle:jdbc:oracle:thin:@127.0.0.1:1521:mydb

username

连接数据库的用户名。

password

连接数据库的密码。如果你不希望密码直接卸载配置文件中,可以使用 ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilter。

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 下建议关闭。

maxOpenPreparedSatements

-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

有两个含义:
1)Destroy 线程会检测连接的间隔时间。2)testWhileIdle的判断依据,详细看 testWhileIdle 属性的说明。

numTestsPerEvictionRun

不再使用,一个 DruidDataSource 只支持一个 EvictionRun。

minEvictableIdleTimeMillis
connectionInitSqls

物理连接初始化的时候执行的sql。

exceptionSorter

根据 dbType 自动识别当数据抛出一些不可恢复的异常时,抛弃连接。

filters

属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
监控统计用的 filter: stat,日志用的 filter: log4j,预防 sql 注入的 filter: wall

proxyFilters

类型是 List<com.alibaba.druid.filter.Filter>,如果同时配置了 filters 和 proxyFilters,是组合关系,并非替换关系。

4.竞品对比

以下是各种数据库连接池对比:
功能类别功能DruidHikariCPDBCPTomcat-jdbcC3P0性能PSCache是否是是是LRU是否是是是SLB负载均衡支持是否否否否稳定性ExceptionSorter是否否否否扩展扩展FilterJdbcIntercepter监控监控方式jmx/log/httpjmx/metricsjmxjmxjmx支持SQL级监控是否否否否Spring/Web关联监控是否否否否诊断支持LogFilter否否否否连接泄露诊断logAbandoned否否否否安全SQL防注入是无无无无支持配置加密是否否否否

二、搭建测试项目

源码地址: https://gitee.com/acgkaka/SpringBootExamples/tree/master/springboot-mybatis-plus-druid

1.Maven依赖

Druid 的 Maven 依赖有两种,

单独依赖

starter依赖

,这里由于我们是 SpringBoot 集成,所以使用

starter依赖

单独依赖:

<!-- Druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.12</version></dependency>

starter依赖:

<!-- Druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.18</version></dependency>

2.yaml配置

官方配置示例: https://github.com/alibaba/druid/blob/master/druid-spring-boot-starter/src/test/resources/application.properties

注意:

spring.datasource.type

并不一定是必须要填的,取决于使用的是 druid 的哪种依赖。

  • 如果使用的是 Druid 的 单独依赖,则必须要设置 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource,否则默认还是使用 Hikari 连接池。
  • 如果使用的是 Druid 的 starter依赖,则不需要手动设置 type,会自动将数据库连接池切换为 Druid。而且 druid-spring-boot-starter 不需要编写配置类,简化了配置。

下面是使用 Druid 的

starter依赖

集成后的配置内容:

官方配置文档: https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

2.1 JDBC配置

方式一:配置在 spring.datasource 下

spring:datasource:# JDBC 配置url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

方式二:配置在 spring.datasource.druid 下

spring:datasource:druid:# JDBC 配置url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

2.2 连接池配置

spring:datasource:druid:# ########## 连接池配置-开始 ##########initial-size:5#初始化大小min-idle:5#最小连接数max-active:20#最大连接数max-wait:60000#配置获取连接等待超时的时间pool-prepared-statements:true#是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。5.5及以上版本有PSCache,建议开启。max-pool-prepared-statement-per-connection-size:20#配置PSCache的大小validation-query: SELECT 1 FROM DUAL #用来检测连接是否有效的sql,要求是一个查询语句,常用SELECT 1 FROM DUALvalidation-query-timeout:3000#检测连接是否有效的超时时间,单位是秒。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法test-on-borrow:false#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能test-on-return:false#是否在归还到池中前进行检验test-while-idle:true#是否在连接池空闲一段时间后检验连接有效性time-between-eviction-runs-millis:60000#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒min-evictable-idle-time-millis:300000#配置一个连接在池中最小生存的时间,单位是毫秒max-evictable-idle-time-millis:600000#配置连接池中连接,在时间段内一直空闲,被逐出连接池的时间,单位毫秒。在minEvictableIdleTimeMillis基础上扩展,会在minEvictableIdleTimeMillis基础上判断连接是否空闲(默认逐出时间就是minEvictableIdleTimeMillis)#max-open-prepared-statements: #和上面的等价#   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙#filters: stat,wall,log4juse-global-data-source-stat:true#是否使用统计connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 #合并多个DruidDataSource的监控数据# ########## 连接池配置-结束 ##########

2.3 监控配置

spring:datasource:druid:# ########## 连接池监控配置-开始 ########### WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilterweb-stat-filter:enabled:true#是否启用StatFilter,默认值falseurl-pattern:'/*'#需要拦截的urlexclusions:'*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'#过滤器忽略的资源session-stat-enable:true#是否开启session统计功能,默认值falsesession-stat-max-count:1000#session统计最大值principal-session-name:#session用户信息principal-cookie-name:#session用户cookie名称profile-enable:true#监控单个url调用的sql列表# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置stat-view-servlet:enabled:true#是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)url-pattern: /druid/* #监控页面拦截urlreset-enable:false#是否启用重置功能login-username: admin #监控页面登录用户名login-password: admin #监控页面登录用户密码#StatViewSerlvet展示出来的监控信息比较敏感,是系统运行的内部情况,如果你需要做访问控制,可以配置allow和deny这两个参数#deny优先于allow,如果在deny列表中,就算在allow列表中,也会被拒绝。如果allow没有配置或者为空,则允许所有访问#配置的格式#<IP>或者<IP>/<SUB_NET_MASK_size>其中128.242.127.1/24,配置多个英文逗号分隔#24表示,前面24位是子网掩码,比对的时候,前面24位相同就匹配,不支持IPV6。allow:#监控页面白名单deny:#黑名单# Spring监控配置,说明请参考Druid Github Wiki,配置_Druid和Spring关联监控配置#aop-patterns: com.demo.*.service.* #Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔# ########## 连接池监控配置-结束 ##########

配置内容涉及参考地址:

补充:

  • 如果需要 Spring 监控,除了配置 aop-patterns 之外,还需要引入 spring-boot-starter-aop 依赖,否则 Spring 监控页面会一片空白。

三、测试

1.查看监控页面

监控页面地址: http://localhost:8081/druid/index.html

访问监控页面,输入账号密码,如果页面中的参数和配置的参数一致,则说明集成成功。

在这里插入图片描述

在这里插入图片描述

2.单元测试

DemoApplicationTests.java

packagecom.demo;importcom.alibaba.druid.pool.DruidDataSource;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjavax.sql.DataSource;importjava.sql.Connection;@SpringBootTestclassDemoApplicationTests{@AutowiredDataSource dataSource;/**
     * 验证数据库连接
     * @throws Exception
     */@TestvoidtestConnection()throwsException{// 默认:class com.zaxxer.hikari.HikariDataSource// Druid:class com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapperSystem.out.println(dataSource.getClass());Connection connection = dataSource.getConnection();// 默认:HikariProxyConnection@1323996324 wrapping com.mysql.cj.jdbc.ConnectionImpl@7c281eb8// Druid:[email protected](connection);
        connection.close();}/**
     * 验证连接池的配置信息,是否生效
     * @throws Exception
     */@TestvoidcontextLoads()throwsException{System.out.println(dataSource.getClass());DruidDataSource druidDataSource =(DruidDataSource) dataSource;System.out.println("initSize:"+ druidDataSource.getInitialSize());System.out.println("maxSize:"+ druidDataSource.getMaxActive());Connection connection = dataSource.getConnection();System.out.println(connection);
        connection.close();}}

连接测试结果:

引入 Druid 连接池依赖之前,执行连接测试,结果如下:(默认使用的是

Hikari

连接池)

在这里插入图片描述

引入 Druid 连接池依赖之后,执行连接测试,结果如下:(改为使用的是

Druid

连接池)

在这里插入图片描述

配置测试结果:

使用 Druid 连接池之后,测试结果如下:

在这里插入图片描述

我们可以看到代码打印的结果与我们的配置一致,说明配置正常生效了。

在这里插入图片描述

源码地址: https://gitee.com/acgkaka/SpringBootExamples/tree/master/springboot-mybatis-plus-druid

四、补充:

1.如何打印慢SQL?

想要在日志中输出慢SQL日志,首先需要进行如下配置:

spring:datasource:druid:filter:stat:enabled:true#是否启用统计slow-sql-millis:5000#慢SQL记录,默认值为3000,单位毫秒log-slow-sql:true#是否打印慢日志merge-sql:true#是否合并SQLdb-type: mysql #数据库类型,用于支持统计分析

除此之外,还需要再

filters

属性中加入项目使用的日志框架,如:

log4j

或者

slf4j

,并引入对应依赖。

logback.xml配置:

<!--druid start--><appendername="DruidFile"class="ch.qos.logback.core.rolling.RollingFileAppender"><File>${LOG_HOME:-d:/}logs/slow_sql/slow_sql.log</File><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><FileNamePattern>${LOG_HOME:-d:/}logs/slow_sql/slow_sql-%d{yyyy-MM-dd}.%i.log
        </FileNamePattern><MaxHistory>60</MaxHistory><TimeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><MaxFileSize>5MB</MaxFileSize></TimeBasedFileNamingAndTriggeringPolicy></rollingPolicy><layoutclass="ch.qos.logback.classic.PatternLayout"><pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n
        </pattern></layout><filterclass="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 --><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><loggername="com.alibaba.druid.filter.stat.StatFilter"additivity="false"><!-- 这里可以按需配置日志级别 --><levelvalue="error"/><appender-refref="DruidFile"/></logger><!--druid end-->

慢SQL日志:

根据 logback.xml 配置,会产生慢 SQL 日志

slow_sql.log

,内容如下所示:

[ERROR]2022-08-3022:44:15.651[http-nio-8080-exec-1] c.a.druid.filter.stat.StatFilter - slow sql4698 millis.SELECT  id,name,no,create_time,update_time  FROMuser[][ERROR]2022-08-3022:57:15.183[http-nio-8080-exec-2] c.a.druid.filter.stat.StatFilter - slow sql3645 millis.SELECT  id,name,no,create_time,update_time  FROMuser[]

2.去除广告

Druid 的监控页面下方有阿里云的广告,可以通过代码去除。

创建

DruidAdConfig.java

配置类:

importcom.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;importcom.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;importcom.alibaba.druid.util.Utils;importorg.springframework.boot.autoconfigure.AutoConfigureAfter;importorg.springframework.boot.autoconfigure.condition.ConditionalOnProperty;importorg.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;importorg.springframework.boot.web.servlet.FilterRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjavax.servlet.*;importjava.io.IOException;/**
 * Druid广告配置
 *
 * @author zzp
 */@Configuration@ConditionalOnWebApplication@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)@ConditionalOnProperty(
        name ="spring.datasource.druid.stat-view-servlet.enabled",
        havingValue ="true",
        matchIfMissing =true)publicclassDruidAdConfig{/**
     * 去除监控页面底部广告
     *
     * @param properties
     * @return org.springframework.boot.web.servlet.FilterRegistrationBean
     */@BeanpublicFilterRegistrationBeanremoveDruidAdFilterRegistrationBean(DruidStatProperties properties){// 获取web监控页面的参数DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();// 提取common.js的配置路径String pattern = config.getUrlPattern()!=null? config.getUrlPattern():"/druid/*";String commonJsPattern = pattern.replaceAll("\\*","js/common.js");finalString filePath ="support/http/resources/js/common.js";// 创建filter进行过滤Filter filter =newFilter(){@Overridepublicvoidinit(FilterConfig filterConfig)throwsServletException{}@OverridepublicvoiddoFilter(ServletRequest request,ServletResponse response,FilterChain chain)throwsIOException,ServletException{
                        chain.doFilter(request, response);// 重置缓冲区,响应头不会被重置
                        response.resetBuffer();// 获取common.jsString text =Utils.readFromResource(filePath);// 正则替换banner, 除去底部的广告信息
                        text = text.replaceAll("<a.*?banner\"></a><br/>","");
                        text = text.replaceAll("powered.*?shrek.wang</a>","");
                        response.getWriter().write(text);}@Overridepublicvoiddestroy(){}};FilterRegistrationBean registrationBean =newFilterRegistrationBean();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns(commonJsPattern);return registrationBean;}}

3.如何手动获取监控内容

官方说明: https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

  • Druid 的监控数据可以在开启 StatFilter 后通过 DruidStatManagerFacade 进行获取。
  • 获取到监控数据之后你可以将其暴露给你的监控系统进行使用。Druid 默认的监控系统数据也来源于此。

下面做一个简单的演示,在 SpringBoot 中国你如何通过 HTTP 接口将 Druid 监控数据以 JSON 的形式暴露出去,实际使用中你可以根据你的需要自动地对监控数据、暴露方式进行扩展。

importcom.alibaba.druid.stat.DruidStatManagerFacade;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassDruidStatController{@GetMapping("/druidStat")publicObjectdruidStat(){// DruidStatManagerFacade#getDataSourceStatDataList 该方法可以获取所有数据源的监控数据,// 除此之外 DruidStatManagerFacade 还提供了一些其他方法,你可以按需选择使用。returnDruidStatManagerFacade.getInstance().getDataSourceStatDataList();}}

返回结果如下:

在这里插入图片描述

详细内容如下:

[{"Identity":2122837918,"Name":"DataSource-2122837918","DbType":"mysql","DriverClassName":"com.mysql.cj.jdbc.Driver","URL":"jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai","UserName":"root","FilterClassNames":["com.alibaba.druid.filter.stat.StatFilter"],"WaitThreadCount":0,"NotEmptyWaitCount":0,"NotEmptyWaitMillis":0,"PoolingCount":5,"PoolingPeak":5,"PoolingPeakTime":"2023-07-08T16:29:24.569+0000","ActiveCount":0,"ActivePeak":0,"ActivePeakTime":null,"InitialSize":5,"MinIdle":5,"MaxActive":20,"QueryTimeout":0,"TransactionQueryTimeout":0,"LoginTimeout":0,"ValidConnectionCheckerClassName":"com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker","ExceptionSorterClassName":"com.alibaba.druid.pool.vendor.MySqlExceptionSorter","TestOnBorrow":false,"TestOnReturn":false,"TestWhileIdle":true,"DefaultAutoCommit":true,"DefaultReadOnly":null,"DefaultTransactionIsolation":null,"LogicConnectCount":0,"LogicCloseCount":0,"LogicConnectErrorCount":0,"PhysicalConnectCount":5,"PhysicalCloseCount":0,"PhysicalConnectErrorCount":0,"DiscardCount":0,"ExecuteCount":0,"ExecuteUpdateCount":0,"ExecuteQueryCount":0,"ExecuteBatchCount":0,"ErrorCount":0,"CommitCount":0,"RollbackCount":0,"PSCacheAccessCount":0,"PSCacheHitCount":0,"PSCacheMissCount":0,"StartTransactionCount":0,"TransactionHistogram":[0,0,0,0,0,0,0],"ConnectionHoldTimeHistogram":[0,0,0,0,0,0,0,0],"RemoveAbandoned":false,"ClobOpenCount":0,"BlobOpenCount":0,"KeepAliveCheckCount":0,"KeepAlive":false,"FailFast":false,"MaxWait":60000,"MaxWaitThreadCount":-1,"PoolPreparedStatements":true,"MaxPoolPreparedStatementPerConnectionSize":20,"MinEvictableIdleTimeMillis":300000,"MaxEvictableIdleTimeMillis":600000,"LogDifferentThread":true,"RecycleErrorCount":0,"PreparedStatementOpenCount":0,"PreparedStatementClosedCount":0,"UseUnfairLock":false,"InitGlobalVariants":false,"InitVariants":false}]

整理完毕,完结撒花~ 🌻

参考地址:

1.Springboot 整合 druid,https://blog.csdn.net/qq_51133939/article/details/126248389

2.SpringBoot配置Druid,https://blog.csdn.net/promsing/article/details/126446143

3.Springboot 集成Druid,https://blog.csdn.net/qq_34285557/article/details/125945877

4.druid慢sql监控,https://blog.csdn.net/xixingzhe2/article/details/126614581

标签: spring boot 后端 java

本文转载自: https://blog.csdn.net/qq_33204709/article/details/131618409
版权归原作者 ACGkaka_ 所有, 如有侵权,请联系我们删除。

“SpringBoot实战(二十)集成Druid连接池”的评论:

还没有评论