当前位置:   article > 正文

druid删除数据_Spring Boot(六):那些好用的数据库连接池们

spring.datasource.druid.filter.wall.config

291db23400e1b8d2b9398a4a98242603.png

数据库连接池,在我们与数据库操作工程中所起的作用可谓是巨大的,尤其是需要频繁操作数据库的情况下。

简单来说,它作为一个连接池,来管理数据库的连接,避免了数据库每次执行sql语句,都要去重新创建连接导致的性能灾难

目前最热门的数据库连接池,就要属阿里巴巴的Druid以及HikariCP了,它们也分别是Spring Boot 1.x和Spring Boot 2.x默认的数据库连接池。因此,今天我们主要来聊聊这两种好用的数据库连接池

689619dd09915672f549a99f654d43a3.png

一 理论 HikariCP

官网地址:https://github.com/brettwooldridge/HikariCP

d10f0fad83e238cffd8fa9b89efc7b14.png

图一

da19cdce746d2a00ea0165eadd0f4ed1.png

图二

这两个图分别为官网中的内容,图一主要表明了HicariCP连接池的特点,快如光速

图二,则表示与其他各个连接池的比较。连接的创建与关闭和statement的创建和关闭时的效率比较。用测试结果再次说明了它的闪光点:快速

01.特点

显而易见:快速,简单,可靠

02.为什么快

1)字节码级改变(很多方法通过JavaAssist生成)

HikariCP利用了一个第三方的Java字节码修改类库Javassist来生成委托实现动态代理

动态代理的实现在ProxyFactory类,源码如下

0694ecdf601355f678593dbb12ad9ff3.png

我们发现这些代理方法中只有一行抛异常的处理代码,注释写着“Body is replaced (injected) by JavassistProxyFactory”,其实方法body中的代码是在编译时调用JavassistProxyFactory才生成的,编译后的JavassistProxyFactory.class类代码如下图

0694ecdf601355f678593dbb12ad9ff3.png

之所以使用Javassist生成动态代理,是因为其速度更快,相比于JDK Proxy生成的字节码更少,精简了很多不必要的字节码

2)大量小改进

a 用FastList替代ArrayList

我们知道,JDBC连接数据库的6大步骤中,到了最后一步需要关闭资源时,关闭Statement时,必须将其从此集合中删除;关闭Connection时,必须迭代该集合并关闭所有打开的Statement实例,最后必须清除该集合

ArrayList本来用于在ProxyConnection类中跟踪、管理打开的Statement实例。HikariCP则使用定制化修改的FastList<Statement>替换ArrayList <Statement>实例

而为何这样就会加快效率呢?

b5e1ac74ffce3a320a8784e47fe13aed.png

ArrayList执行get(int index)方法时,对每个对象都要检查。而使用FastList则不需要

23ecfb5cbc863c7e0a3e7edda3d7bf75.png

4e4c566f12afe2e2c805fb69533c5b42.png

可以看到,使用FastList时,由于直接定义的就是一个固定长度的数组,那么范围就是可以保证的,因此在get方法中,直接使用元素索引找到特定元素,就不需要对每个对象都进行检查了

此外,ArrayList的remove(Object)是从头到尾进行扫描,但是JDBC编程中的常见模式是在使用后立即关闭Statement,或者以打开的相反顺序关闭Statement。对于这些情况,其实从尾部开始的扫描会更好

64f99cf0251b30b3cf2ff7c97732d375.png

我们可以看到,FastList改造了remove(Object)方法,采用从后往前的顺序进行对象的删除

因此,将ArrayList <Statement>替换为自定义类FastList,该类消除了范围检查执行了从尾到头的删除扫描,大大提升了执行效率

b 无锁集合 ConcurrentBag

HikariCP包含一个名为ConcurrentBag的自定义无锁集合

这是一个专门的并发包,可以为连接池实现LinkedBlockingQueue和LinkedTransferQueue的卓越性能。它尽可能使用ThreadLocal存储来避免锁定,但如果ThreadLocal列表中没有可用的项目,则会使用它来扫描公共集合

当借用线程没有自己的东西时,ThreadLocal列表中的未使用项可能被“窃取”。它是一个“无锁”实现,使用专门的AbstractQueuedLongSynchronizer来管理跨线程信令

c 代理类的优化

比如用invokestatic代替invokevirtual。此更改从堆栈中删除了静态字段访问,推入和弹出操作,并因为保证了呼叫站点不会更改,使得JIT可以更轻松地优化调用

03.Spring Boot对它的支持

它是Spring Boot 2.x默认数据连接池。因此,要想使用它来操作数据库,可以无需配置数据库连接池,Spring Boot默认就进行了配置

那么Spring Boot 是如何实现自动使用HikariCP数据库连接池的呢?

1)首先,Spring Boot的starter-jdbc依赖中,就自动引入了HikariCP连接池的依赖

27a50f170137011269ff5f02f5f38de8.png

2)查看数据库配置类DataSourceConfiguration对HicariCP的配置

当定义了HikariDataSource类(存在于第一步中自动引入的HicariCP依赖中),未定义DataSource类,并且有spring.datasource.type属性为com.zaxxer.hikari.HikariDataSource,当然matchIfMissing = true表示即使不设置,也符合条件

使用前缀为spring.datasource.hikari,对DataSourceProperties中的各个属性进行默认配置,然后创建配置数据源(如果application.properties中先需要覆盖这些属性的值,则需要配置的名称表示为前缀名+DataSourceProperties中的属性名称),如:spring.datasource.hikari.url

就这样,两个步骤的配合,就实现了Spring Boot 2.x对HicariCP的默认支持

04.监控功能

HikariCP提供了一些监控指标,他的监控指标都是基于MicroMeter提供出来的,然后支持Prometheus和Dropwizard。具体如何实现,本次暂不做讲解。如有疑问,可随时沟通

二 理论 Druid

Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能。功能强大,能防SQL注入,内置Loging能诊断Hack应用行为

01. 稳定特性

扛得住双十一,稳定性你想呢?

02. 为监控而生

Druid增加StatFilter之后,能采集大量统计信息,同时对性能基本没有影响。StatFilter对CPU和内存的消耗都极小,对系统的影响可以忽略不计

监控不影响性能是Druid连接池的重要特性

1)执行次数、返回行数、更新行数和并发监控

StatFilter能采集到每个SQL的执行次数返回行数总和更新行数总和执行中次数和最大并发。并发监控的统计是在SQL执行开始对计数器加一,结束后对计数器减一实现的。可以采集到每个SQL的当前并发和采集期间的最大并发

2)慢查监控

通过如下所示配置慢sql打印,可以打印出慢sql的执行时间,具体sql语句的打印输出

  1. #慢sql打印配置
  2. spring.datasource.druid.filter.stat.log-slow-sql=true
  3. spring.datasource.druid.filter.stat.slow-sql-millis=100

03. 众多扩展点

众多扩展点,方便进行定制

78f224c38bc808fa25511f5c226bb3c0.png

各个扩展点分别通过继承类FilterEventAdapter,分别进行不同功能的扩展。通过源码可以看到,包括建立连接之前,statement执行sql语句之前、之后可以做什么等

其中config负责进行加解密相关工作,stat负责监控,slf4j则负责与log4j配合进行日志输出

如果我们要实现功能扩展的话,也只需要同样继承FilterEventAdapter,实战环节会有扩展示例哦~

04. 防sql注入

通过一些配置项,可以轻易实现防sql注入功能

如以下配置实现mysql数据库中禁止删表、删除数据操作

  1. #sql防注入配置
  2. spring.datasource.druid.filter.wall.enabled=true
  3. spring.datasource.druid.filter.wall.db-type=mysql
  4. #设置数据库不可以执行删除、删表操作
  5. spring.datasource.druid.filter.wall.config.delete-allow=false
  6. spring.datasource.druid.filter.wall.config.drop-table-allow=false

04. ExceptionSorter

ExceptionSorter-对各种主流数据库的返回码都有定制

下面是ExceptionSorter接口,各个数据库实现类通过实现这个接口,进行方法的定制化覆盖

93e65cef46539f4b503910dce7c6d234.png

Spring Boot会根据我们引入的数据库驱动依赖,来对应不同数据库的返回码处理

05. 内置加密配置

三 实战 实战环节

相信大家对两种数据源已经有了一定的了解了,接下来就分别看看在Spring Boot(2.x)中分别如何使用这它们吧

01. Spring Boot 使用HicariCP

由于在Spring Boot 2.x中,只要需要操作数据库,就需要引入JDBC依赖(Mybatis和JPA对应的依赖中都包含了JDBC依赖),而我们在理论环节都已经发现了,JDBC中已经引入了HicariCP依赖

即Spring Boot 2.x已经默认支持了HicariCP,我们需要做的就只需要关心数据库操作相关功能即可,完成这些,直接运行项目即可

注意:关于Spring Boot 连接数据库的具体操作,可分别参考前几次文章。由于使用这两种连接池的区别主要是依赖和配置文件中配置项名称的区别,因此本次实战只做依赖、配置演示

1)引入依赖

57d7098f5ae169617f578807f8fa2301.png

2) 属性配置

  1. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8
  2. spring.datasource.username=root
  3. spring.datasource.password=123456
  4. #可以不用配置数据库驱动,SpringBoot 会根据引入的依赖进行自动配置
  5. #spring.datasource.driver-class-name=com.mysql.jdbc.Driver

3)项目启动

日志打印如下:

3ec84eda9ea08cd3a178f593355733fe.png

如图所示,项目默认使用的是HicariCP连接池

02. Spring Boot 使用Druid

1)引入依赖

1e8afa5ea76574f3a03daf8263ea5e92.png

引入druid数据源,并排除掉jdbc中的HicariCP依赖。

Tips:

虽然经测试发现,不排除HicariCP依赖,Spring Boot 也会直接使用主动引入的Druid,但是为了项目的简洁,以及可管理性,尽量排除掉比较好

2)属性配置

  1. spring.datasource.druid.initial-size=5
  2. spring.datasource.druid.max-active=5
  3. spring.datasource.druid.min-idle=5
  4. spring.datasource.druid.filter.config.enabled=true
  5. #其中conn为自己扩展的
  6. spring.datasource.druid.filters=conn,config,stat,slf4j
  7. #spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=${public-key}
  8. spring.datasource.druid.test-on-borrow=true
  9. spring.datasource.druid.test-on-return=true
  10. spring.datasource.druid.test-while-idle=true
  11. #慢sql打印配置
  12. spring.datasource.druid.filter.stat.log-slow-sql=true
  13. spring.datasource.druid.filter.stat.slow-sql-millis=1
  14. #public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALS8ng1XvgHrdOgm4pxrnUdt3sXtu/E8My9KzX8sXlz+mXRZQCop7NVQLne25pXHtZoDYuMh3bzoGj6v5HvvAQ8CAwEAAQ==
  15. #sql防注入配置
  16. spring.datasource.druid.filter.wall.enabled=true
  17. spring.datasource.druid.filter.wall.db-type=mysql
  18. spring.datasource.druid.filter.wall.config.delete-allow=false
  19. spring.datasource.druid.filter.wall.config.drop-table-allow=false

3)功能扩展

a 自定义扩展类ConnectionLogFilter

继承FilterEventAdapter,并分别实现建立连接前、后的操作

  1. @Slf4j
  2. public class ConnectionLogFilter extends FilterEventAdapter {
  3. @Override
  4. public void connection_connectBefore(FilterChain chain,
  5. Properties info) {
  6. log.info("BEFORE CONNECTION!");
  7. }
  8. @Override
  9. public void connection_connectAfter(ConnectionProxy connection) {
  10. log.info("AFTER CONNECTION!");
  11. }
  12. }

b 创建druid-filter.properties文件,配置该扩展类

526a07f838006ca9748c57ef85573c28.png

c 配置类中进行配置

spring.datasource.druid.filters=conn,config,stat,slf4j

即在spring.datasource.druid.filters项中,添加conn

4)项目启动

如下所示,项目已经切换到了druid连接池。并实现了扩展类

accc9f3918eaef0c5975ecaa8437147a.png

四 总结 总而言之

今天主要聊了一下HicariCP和Druid这两个常用的数据库连接池。其实两个作为连接池还是挺不错的,HikariCP的功能比较纯粹一些,对性能有极大地积极作用,Druid内置的功能会更丰富,可扩展的点比较多。

建议如果只是纯粹拿来做连接池,HikariCP就挺好的。如果有自己定制各种功能的需求,比如密码加密、监控功能等,Druid会有更好扩展。

本人实际开发中使用的Druid连接池会更多一些,你呢?

总结:

1、HicariCP数据库连接池的特点-为什么快

2、Druid数据库连接池的特点-为监控而生

3、Spring Boot对两种连接池的支持

嗯,就这样。每天学习一点,时间会见证你的强大。

下期预告:

Spring Boot(七):聊聊mybatis的缓存

本期项目代码已上传到github~有需要的可以参考

https://github.com/wangjie0919/Spring-Boot-Notes

往期精彩回顾

Spring Boot(五):春眠不觉晓,Mybatis知多少

Spring Boot(四):让人又爱又恨的JPA

Spring Boot(三):操作数据库-Spring JDBC

SpringBoot(二):第一个Spring Boot项目

SpringBoot(一):特性概览

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/336889
推荐阅读
相关标签
  

闽ICP备14008679号