SpringBoot使用Druid监控SQL
1 监控mybatis下SQL
1.1 Druid简介
Druid
是阿里巴巴开发的号称为监控而生的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource
等等等,秒杀一切。
Druid
可以很好的监控 DB
池连接和 SQL
的执行情况,天生就是针对监控而生的 DB
连接池。
Spring Boot
默认数据源 HikariDataSource
与 JdbcTemplate
中已经介绍 Spring Boot 2.x
默认使用 Hikari
数据源,可以说 Hikari
与 Driud
都是当前 Java
Web
上最优秀的数据源。
其中的监控器:
stat
:Druid
内置提供一个StatFilter
,用于统计监控信息。wall
:Druid
防御SQL
注入攻击的WallFilter
就是通过Druid
的SQL Parser
分析。Druid
提供的SQL Parser
可以在JDBC
层拦截SQL
做相应处理,比如说分库分表、审计等。log4j2
:这个就是 日志记录的功能,可以把sql
语句打印到log4j2
供排查问题。
1.2 添加pom.xml依赖
<!-- 阿里巴巴的druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
<!-- mysql8 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--使用 log4j2 记录日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--
mybatis,引入了 SpringBoot的 JDBC 模块,
所以,默认是使用 hikari 作为数据源
-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
<exclusions>
<!-- 排除默认的 HikariCP 数据源 -->
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
1.3 配置相关属性
- 配置
Druid
数据源(连接池): 如同以前 c3p0、dbcp 数据源可以设置数据源连接初始化大小、最大连接数、等待时间、最小连接数 等一样,Druid
数据源同理可以进行设置; - 配置
Druid web
监控filter
(WebStatFilter
): 这个过滤器的作用就是统计web
应用请求中所有的数据库信息,比如 发出的 sql 语句,sql 执行的时间、请求次数、请求的 url 地址、以及seesion 监控、数据库表的访问次数 等等。 - 配置
Druid
后台管理Servlet
(StatViewServlet
):Druid
数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装路由器 时,人家也提供了一个默认的 web 页面;需要设置 Druid 的后台管理页面的属性,比如 登录账号、密码 等;
注意:
Druid Spring Boot Starter
配置属性的名称完全遵照 Druid
,可以通过 Spring Boot
配置文件来配置Druid
数据库连接池和监控,如果没有配置则使用默认值。
application.yml
########## 配置数据源 (Druid)##########
spring:
datasource:
########## JDBC 基本配置 ##########
username: xxx
password: xxx
driver-class-name: com.mysql.cj.jdbc.Driver # mysql8 的连接驱动
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai
platform: mysql # 数据库类型
type: com.alibaba.druid.pool.DruidDataSource # 指定数据源类型
########## 连接池 配置 ##########
druid:
# 配置初始化大小、最小、最大
initial-size: 5
minIdle: 10
max-active: 20
# 配置获取连接等待超时的时间(单位:毫秒)
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 2000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 600000
max-evictable-idle-time-millis: 900000
# 用来测试连接是否可用的SQL语句,默认值每种数据库都不相同,这是mysql
validationQuery: select 1
# 应用向连接池申请连接,并且testOnBorrow为false时,连接池将会判断连接是否处于空闲状态,如果是,则验证这条连接是否可用
testWhileIdle: true
# 如果为true,默认是false,应用向连接池申请连接时,连接池会判断这条连接是否是可用的
testOnBorrow: false
# 如果为true(默认false),当应用使用完连接,连接池回收连接的时候会判断该连接是否还可用
testOnReturn: false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle
poolPreparedStatements: true
# 要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true,
# 在Druid中,不会存在Oracle下PSCache占用内存过多的问题,
# 可以把这个数值配置大一些,比如说100
maxOpenPreparedStatements: 20
# 连接池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作
keepAlive: true
# Spring 监控,利用aop 对指定接口的执行时间,jdbc数进行记录
aop-patterns: "com.springboot.template.dao.*"
########### 启用内置过滤器(第一个 stat必须,否则监控不到SQL)##########
filters: stat,wall,log4j2
# 自己配置监控统计拦截的filter
filter:
# 开启druiddatasource的状态监控
stat:
enabled: true
db-type: mysql
# 开启慢sql监控,超过2s 就认为是慢sql,记录到日志中
log-slow-sql: true
slow-sql-millis: 2000
# 日志监控,使用slf4j 进行日志输出
slf4j:
enabled: true
statement-log-error-enabled: true
statement-create-after-log-enabled: false
statement-close-after-log-enabled: false
result-set-open-after-log-enabled: false
result-set-close-after-log-enabled: false
########## 配置WebStatFilter,用于采集web关联监控的数据 ##########
web-stat-filter:
enabled: true # 启动 StatFilter
url-pattern: /* # 过滤所有url
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" # 排除一些不必要的url
session-stat-enable: true # 开启session统计功能
session-stat-max-count: 1000 # session的最大个数,默认100
########## 配置StatViewServlet(监控页面),用于展示Druid的统计信息 ##########
stat-view-servlet:
enabled: true # 启用StatViewServlet
url-pattern: /druid/* # 访问内置监控页面的路径,内置监控页面的首页是/druid/index.html
reset-enable: false # 不允许清空统计数据,重新计算
login-username: root # 配置监控页面访问密码
login-password: 123
allow: 127.0.0.1 # 允许访问的地址,如果allow没有配置或者为空,则允许所有访问
deny: # 拒绝访问的地址,deny优先于allow,如果在deny列表中,就算在allow列表中,也会被拒绝
上述配置文件的参数可以在 com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties
和 org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
中找到;
1.3.1 如何配置 Filter
可以通过spring.datasource.druid.filters=stat,wall,log4j ...
的方式来启用相应的内置Filter
,不过这些Filter
都是默认配置。如果默认配置不能满足需求,可以放弃这种方式,通过配置文件来配置Filter
,下面是例子。
# 配置StatFilter
spring.datasource.druid.filter.stat.enabled=true
spring.datasource.druid.filter.stat.db-type=h2
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=2000
# 配置WallFilter
spring.datasource.druid.filter.wall.enabled=true
spring.datasource.druid.filter.wall.db-type=h2
spring.datasource.druid.filter.wall.config.delete-allow=false
spring.datasource.druid.filter.wall.config.drop-table-allow=false
目前为以下 Filter
提供了配置支持,根据(spring.datasource.druid.filter.*)进行配置。
StatFilter
WallFilter
ConfigFilter
EncodingConvertFilter
Slf4jLogFilter
Log4jFilter
Log4j2Filter
CommonsLogFilter
不想使用内置的 Filters
,要想使自定义 Filter
配置生效需要将对应 Filter
的 enabled
设置为 true
,Druid Spring Boot Starter
默认禁用 StatFilter
,可以将其 enabled
设置为 true
来启用它。
1.4 监控页面
启动项目后,访问/druid/login.html
来到登录页面,输入用户名密码登录
数据源页面 是当前DataSource
配置的基本信息,上述配置的Filter
可以在里面找到,如果没有配置Filter
(一些信息会无法统计,例如“SQL监控”,会无法获取JDBC相关的SQL执行信息)
SQL
监控页面,统计了所有SQL
语句的执行情况
URL
监控页面,统计了所有Controller
接口的访问以及执行情况
Spring
监控页面,利用aop
对指定接口的执行时间,jdbc数进行记录
SQL
防火墙页面
druid
提供了黑白名单的访问,可以清楚的看到sql
防护情况。
Session
监控页面
可以看到当前的session状况,创建时间、最后活跃时间、请求次数、请求时间等详细参数。
JSONAPI 页面
通过api的形式访问Druid的监控接口,api接口返回Json形式数据。
1.5 sql监控
配置 Druid web
监控 filter
(WebStatFilter
)这个过滤器,作用就是统计 web
应用请求中所有的数据库信息,比如 发出的 sql 语句,sql
执行的时间、请求次数、请求的 url 地址、以及seesion
监控、数据库表的访问次数 等等。
spring:
datasource:
druid:
########## 配置WebStatFilter,用于采集web关联监控的数据 ##########
web-stat-filter:
enabled: true # 启动 StatFilter
url-pattern: /* # 过滤所有url
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" # 排除一些不必要的url
session-stat-enable: true # 开启session统计功能
session-stat-max-count: 1000 # session的最大个数,默认100
1.6 慢sql记录
有时候,系统中有些SQL
执行很慢,我们希望使用日志记录下来,可以开启Druid
的慢SQL
记录功能
spring:
datasource:
druid:
filter:
stat:
enabled: true # 开启DruidDataSource状态监控
db-type: mysql # 数据库的类型
log-slow-sql: true # 开启慢SQL记录功能
slow-sql-millis: 2000 # 默认3000毫秒,这里超过2s,就是慢,记录到日志
启动后,如果遇到执行慢的SQL,便会输出到日志中。
1.7 spring 监控
访问之后spring
监控默认是没有数据的;这需要导入SprngBoot
的AOP
的Starter
<!--SpringBoot 的aop 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
需要在 application.yml
配置:
Spring
监控AOP
切入点,如com.springboot.template.dao.*,
(配置多个英文逗号分隔)
spring.datasource.druid.aop-patterns="com.springboot.template.dao.*"
1.8 去 Ad(广告)
访问监控页面的时候,可能会在页面底部(footer)看到阿里巴巴的广告
原因:引入的druid
的jar包中的common.js
(里面有一段js代码是给页面的footer
追加广告的)
如果想去掉,有两种方式:
- 直接手动注释这段代码
如果是使用Maven
,直接到本地仓库中,查找这个jar包
要注释的代码:
// this.buildFooter();
common.js的位置:
com/alibaba/druid/1.1.23/druid-1.1.23.jar!/support/http/resources/js/common.js
- 使用过滤器过滤
注册一个过滤器,过滤common.js
的请求,使用正则表达式替换相关的广告内容
@Configuration
@ConditionalOnWebApplication
@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled",
havingValue = "true", matchIfMissing = true)
public class RemoveDruidAdConfig {
/**
* 方法名: removeDruidAdFilterRegistrationBean
* 方法描述 除去页面底部的广告
* @param properties com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties
* @return org.springframework.boot.web.servlet.FilterRegistrationBean
*/
@Bean
public FilterRegistrationBean removeDruidAdFilterRegistrationBean(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");
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.js
String text = Utils.readFromResource(filePath);
// 正则替换banner, 除去底部的广告信息
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
text = text.replaceAll("powered.*?shrek.wang</a>", "");
response.getWriter().write(text);
}
@Override
public void destroy() {}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}
两种方式都可以,建议使用的是第一种,从根源解决
1.9 获取Druid的监控数据
Druid
的监控数据可以在开启StatFilter
后,通过DruidStatManagerFacade
进行获取;
DruidStatManagerFacade#getDataSourceStatDataList
该方法可以获取所有数据源的监控数据,
除此之外 DruidStatManagerFacade
还提供了一些其他方法,可以按需选择使用
@RestController
@RequestMapping(value = "/druid")
public class DruidStatController {
@GetMapping("/stat")
public Object druidStat(){
// 获取数据源的监控数据
return DruidStatManagerFacade.getInstance().getDataSourceStatDataList();
}
}
虽然 HikariCP
的速度稍快,但是,Druid
能够提供强大的监控和扩展功能,也是阿里巴巴的开源项目。
Druid
是阿里巴巴开发的号称为监控而生的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池
转载于:https://mp.weixin.qq.com/s/rc1Y2u8qD8hRoMhbqhFmRA
2 监控mybatis-plus下SQL
2.1 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--注意引入druid需要引入log4j,不然会报错-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
2.2 application.yml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost/springboot?characterEncoding=utf-8&useSSl=false
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#监控统计拦截的filters
filters: stat,wall,log4j
#druid配置
#配置初始化大小/最小/最大
initialSize: 5
minIdle: 5
maxActive: 20
#获取连接等待超时时间
maxWait: 60000
#间隔多久进行一次检测,检测需要关闭的空闲连接
timeBetweenEvictionRunsMillis: 60000
#一个连接在池中最小生存的时间
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
#打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
poolPreparedStatements: false
maxPoolPreparedStatementPerConnectionSize: 20
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties:
druid:
stat:
mergeSql: true
slowSqlMillis: 5000
#mybatis是独立节点,需要单独配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.frank.securityjwt.entity
configuration:
map-underscore-to-camel-case: true
2.3 相关配置信息
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.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.PropertySource;
import javax.sql.DataSource;
@Configuration
@PropertySource(value = "classpath:application.yml")
public class DruidConfiguration {
/**
* @todo 数据源配置
*/
@Bean(destroyMethod = "close", initMethod = "init")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
/**
* druid
* 注册一个StatViewServlet
* @return
*/
@Bean
public ServletRegistrationBean druidStatViewServlet(){
//org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
//添加初始化参数:initParams
//白名单:
servletRegistrationBean.addInitParameter("allow","127.0.0.1");
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
//servletRegistrationBean.addInitParameter("deny","192.168.1.73");
//登录查看信息的账号密码.
servletRegistrationBean.addInitParameter("loginUsername","admin");
servletRegistrationBean.addInitParameter("loginPassword","123456");
//是否能够重置数据.
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
}
/**
* druid过滤器
* 注册一个:filterRegistrationBean
* @return
*/
@Bean
public FilterRegistrationBean druidStatFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则.
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息.
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}