上一节, 我们介绍了 Spring Boot 在 JDBC 模块中自动化配置使用的默认数据源 HikariCP. 接下来这一节, 我们将介绍另外一个被广泛应用的开源数据源: Druid.
Druid https://github.com/alibaba/druid 是由阿里巴巴数据库事业部出品的开源项目. 它除了是一个高性能数据库连接池之外, 更是一个自带监控的数据库连接池. 虽然 HikariCP 已经很优秀, 但是对于国内用户来说, 可能对于 Druid 更为熟悉. 所以, 对于如何在 Spring Boot 中使用 Druid 是后端开发人员必须要掌握的基本技能.
配置 Druid 数据源
这一节的实践我们将基于《Spring Boot 2.x 基础教程: 使用 JdbcTemplate 访问 MySQL 数据库》一文的代码基础上进行. 所以, 读者可以从文末的代码仓库中, 检出 chapter3-1 目录来进行下面的实践学习.
下面我们就来开始对 Spring Boot 项目配置 Druid 数据源:
第一步: 在 pom.xml 中引入 druid 官方提供的 Spring Boot Starter 封装.
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.21</version>
- </dependency>
第二步: 在 application.properties 中配置数据库连接信息.
Druid 的配置都以 spring.datasource.druid 作为前缀, 所以根据之前的配置, 稍作修改即可:
- spring.datasource.druid.url=jdbc:MySQL://localhost:3306/test
- spring.datasource.druid.username=root
- spring.datasource.druid.password=
- spring.datasource.druid.driver-class-name=com.MySQL.cj.jdbc.Driver
第三步: 配置 Druid 的连接池.
与 Hikari 一样, 要用好一个数据源, 就要对其连接池做好相应的配置, 比如下面这样:
spring.datasource.druid.initialSize=10 spring.datasource.druid.maxActive=20 spring.datasource.druid.maxWait=60000 spring.datasource.druid.minIdle=1 spring.datasource.druid.timeBetweenEvictionRunsMillis=60000 spring.datasource.druid.minEvictableIdleTimeMillis=300000 spring.datasource.druid.testWhileIdle=true spring.datasource.druid.testOnBorrow=true spring.datasource.druid.testOnReturn=false spring.datasource.druid.poolPreparedStatements=true spring.datasource.druid.maxOpenPreparedStatements=20 spring.datasource.druid.validationQuery=SELECT 1 spring.datasource.druid.validation-query-timeout=500 spring.datasource.druid.filters=stat
关于 Druid 中各连接池配置的说明可查阅下面的表格:
配置 | 缺省值 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。如果没有配置,将会生成一个名字,格式是:”DataSource-“ + System.identityHashCode(this). 另外配置此属性至少在 1.0.5 版本中是不起作用的,强行设置 name 会出错。 详情 - 点此处 。 | |
url | 连接数据库的 url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用 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 下建议关闭。 |
maxPoolPreparedStatementPerConnectionSize | -1 | 要启用 PSCache,必须配置大于 0,当大于 0 时,poolPreparedStatements 自动触发修改为 true。在 Druid 中,不会存在 Oracle 下 PSCache 占用内存过多的问题,可以把这个数值配置大一些,比如说 100 |
validationQuery | 用来检测连接是否有效的 sql,要求是一个查询语句,常用 select ‘x’。如果 validationQuery 为 null,testOnBorrow、testOnReturn、testWhileIdle 都不会起作用。 | |
validationQueryTimeout | 单位:秒,检测连接是否有效的超时时间。底层调用 jdbc Statement 对象的 void setQueryTimeout(int seconds) 方法 | |
testOnBorrow | true | 申请连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。 |
testWhileIdle | false | 建议配置为 true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis,执行 validationQuery 检测连接是否有效。 |
keepAlive | false (1.0.28) | 连接池中的 minIdle 数量以内的连接,空闲时间超过 minEvictableIdleTimeMillis,则会执行 keepAlive 操作。 |
timeBetweenEvictionRunsMillis | 1 分钟(1.0.14) | 有两个含义: 1) Destroy 线程会检测连接的间隔时间,如果连接空闲时间大于等于 minEvictableIdleTimeMillis 则关闭物理连接。 2) testWhileIdle 的判断依据,详细看 testWhileIdle 属性的说明 |
numTestsPerEvictionRun | 30 分钟(1.0.14) | 不再使用,一个 DruidDataSource 只支持一个 EvictionRun |
minEvictableIdleTimeMillis | 连接保持空闲而不被驱逐的最小时间 | |
connectionInitSqls | 物理连接初始化的时候执行的 sql | |
exceptionSorter | 根据 dbType 自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的 filter:stat 日志用的 filter:log4j 防御 sql 注入的 filter:wall | |
proxyFilters | 类型是 List<com.alibaba.druid.filter.Filter>,如果同时配置了 filters 和 proxyFilters,是组合关系,并非替换关系 |
到这一步, 就已经完成了将 Spring Boot 的默认数据源 HikariCP 切换到 Druid 的所有操作.
配置 Druid 监控
既然用了 Druid, 那么对于 Druid 的监控功能怎么能不用一下呢? 下面就来再进一步做一些配置, 来启用 Druid 的监控.
第一步: 在 pom.xml 中引入 spring-boot-starter-actuator 模块
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
第二步: 在 application.properties 中添加 Druid 的监控配置.
spring.datasource.druid.stat-view-servlet.enabled=true spring.datasource.druid.stat-view-servlet.url-pattern=/druid/* spring.datasource.druid.stat-view-servlet.reset-enable=true spring.datasource.druid.stat-view-servlet.login-username=admin spring.datasource.druid.stat-view-servlet.login-password=admin
上面的配置主要用于开启 stat 监控统计的界面以及监控内容的相关配置, 具体释意如下:
spring.datasource.druid.stat-view-servlet.url-pattern
: 访问地址规则
spring.datasource.druid.stat-view-servlet.reset-enable
: 是否允许清空统计数据
spring.datasource.druid.stat-view-servlet.login-username
: 监控页面的登录账户
spring.datasource.druid.stat-view-servlet.login-password
: 监控页面的登录密码
第三步: 针对之前实现的 UserService 内容, 我们创建一个 Controller 来通过接口去调用数据访问操作:
@Data @AllArgsConstructor @RestController public class UserController { private UserService userService; @PostMapping("/user") public int create(@RequestBody User user) { return userService.create(user.getName(), user.getAge()); } @GetMapping("/user/{name}") public List<User> getByName(@PathVariable String name) { return userService.getByName(name); } @DeleteMapping("/user/{name}") public int deleteByName(@PathVariable String name) { return userService.deleteByName(name); } @GetMapping("/user/count") public int getAllUsers() { return userService.getAllUsers(); } @DeleteMapping("/user/all") public int deleteAllUsers() { return userService.deleteAllUsers(); } }
第四步: 完成上面所有配置之后, 启动应用, 访问 Druid 的监控页面 http://localhost:8080/druid/, 可以看到如下登录页面:
输入上面 spring.datasource.druid.stat-view-servlet.login-username 和 spring.datasource.druid.stat-view-servlet.login-password 配置的登录账户与密码, 就能看到如下监控页面:
进入到这边时候, 就可以看到对于应用端而言的各种监控数据了. 这里讲解几个最为常用的监控页面:
数据源: 这里可以看到之前我们配置的数据库连接池信息以及当前使用情况的各种指标.
SQL 监控: 该数据源中执行的 SQL 语句极其统计数据. 在这个页面上, 我们可以很方便的看到当前这个 Spring Boot 都执行过哪些 SQL, 这些 SQL 的执行频率和执行效率也都可以清晰的看到. 如果你这里没看到什么数据? 别忘了我们之前创建了一个 Controller, 用这些接口可以触发 UserService 对数据库的操作. 所以, 这里我们可以通过调用接口的方式去触发一些操作, 这样 SQL 监控页面就会产生一些数据:
图中监控项上, 执行时间, 读取行数, 更新行数都通过区间分布的方式表示, 将耗时分布成 8 个区间:
0 - 1 耗时 0 到 1 毫秒的次数
1 - 10 耗时 1 到 10 毫秒的次数
10 - 100 耗时 10 到 100 毫秒的次数
100 - 1,000 耗时 100 到 1000 毫秒的次数
1,000 - 10,000 耗时 1 到 10 秒的次数
10,000 - 100,000 耗时 10 到 100 秒的次数
100,000 - 1,000,000 耗时 100 到 1000 秒的次数
1,000,000 - 耗时 1000 秒以上的次数
记录耗时区间的发生次数, 通过区分分布, 可以很方便看出 SQL 运行的极好, 普通和极差的分布. 耗时区分分布提供了 "执行 + RS 时分布", 是将执行时间 + ResultSet 持有时间合并监控, 这个能方便诊断返回行数过多的查询.
SQL 防火墙: 该页面记录了与 SQL 监控不同维度的监控数据, 更多用于对表访问维度, SQL 防御维度的统计.
该功能数据记录的统计需要在 spring.datasource.druid.filters 中增加 wall 属性才会进行记录统计, 比如这样:
spring.datasource.druid.filters=stat,wall
注意: 这里的所有监控信息是对这个应用实例的数据源而言的, 而并不是数据库全局层面的, 可以视为应用层的监控, 不可能作为中间件层的监控.
代码示例
本文的相关例子可以查看下面仓库中的 chapter3-3 目录:
GitHub:
Gitee:
如果您觉得本文不错, 欢迎 Star 支持, 您的关注是我坚持的动力!
来源: https://www.cnblogs.com/didispace/p/12294827.html