目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

连接池

HikariCP

HikariCP 来自于日语,意为:光。 它本身作为 SpringBoot 2.X 默认的连接池。
HikariCP-bench

"Fast"源于深度优化和大量小改进

  • 字节码级别优化(很多方法通过 JavaAssist 生成)
  • 大量小改进:用 FastStatementList 代替 ArrayList、无锁集合 ConcurrentBag 、 代理类的优化(用 invokestatic 代替 invokevirtual)

SpringBoot 中的配置

  • 默认使用 HikariCP
  • application.properties 配置格式 spring.datasource.hikari.*
  • 如果是 SpringBoot 1.x 需要在 maven 中移除默认的 tomcat-jdbc 依赖,并且引入 HikariCP 的 Maven 依赖,并且在 application.properties 配置文件中指定默认的连接池类型 spring.datasource.type=com.zaxxer.hikari.HikariDataSource
 1# 暴露Actuator  
 2management.endpoints.web.exposure.include=*  
 3  
 4# 如果你的终端支持ANSI,设置彩色输出会让日志更具可读性  
 5# DETECT:会检查终端是否支持ANSI,是的话就采用彩色输出(推荐项)  
 6# ALWAYS:总是使用ANSI-colored格式输出,若终端不支持的时候,会有很多干扰信息,不推荐  
 7spring.output.ansi.enabled=ALWAYS  
 8  
 9# 通用配置  
10spring.datasource.url=jdbc:h2:mem:testdb  
11spring.datasource.username=sa  
12spring.datasource.password=  
13#spring.datasource.driver-class-name=com.mysql.jdbc.Driver #(可选),因为springboot会根据spring.datasource.url 自动判断,选择合适的驱动。  
14  
15# 连接池配置  
16spring.datasource.hikari.maximumPoolSize=5  
17spring.datasource.hikari.minimumIdle=5  
18spring.datasource.hikari.idleTimeout=600000  
19spring.datasource.hikari.connectionTimeout=30000  
20spring.datasource.hikari.maxLifetime=1800000

常用配置说明

name description default_value
maximumPoolSize 此属性控制允许池达到的最大大小,包括空闲和使用中的连接。基本上,此值将确定到数据库后端的最大实际连接数。合理的值最好由您的执行环境确定。当池达到此大小并且没有空闲连接可用时,对 getConnection()的调用将 connectionTimeout 在超时之前最多阻塞毫秒。 10
minimumIdle 此属性控制 HikariCP 尝试在池中维护的最小空闲连接数。如果空闲连接下降到该值以下,并且池中的总连接数少于 maximumPoolSize ,则 HikariCP 将尽最大努力快速而有效地添加其他连接。但是,为了获得最佳性能和对峰值需求的响应能力,我们建议不要设置此值,而应让 HikariCP 充当固定大小的连接池。 默认值:与 maximumPoolSize 相同 10
maximumPoolSize
idleTimeout 连接允许在池中闲置的最长时间 600000(10 分钟)
connectionTimeout 此属性控制客户端(即您)等待来自池的连接的最大毫秒数。如果超过此时间而没有可用的连接,则会抛出 SQLException。可接受的最低连接超时为 250 ms。 30000(30 秒)
maxLifetime 用来设置一个 connection 在连接池中的存活时间 1800000,即 30 分钟。如果设置为 0,表示存活时间无限大。如果不等于 0 且小于 30 秒则会被重置回 30 分钟。
更多配置 官网

Alibaba Druid

 “Druid 连接池是阿 ⾥巴巴开源的数据库连接池项 ⽬。Druid 连接池为监控而生,内置强 ⼤的监控功能,监控特性不影响性能。功能强 ⼤,能防 SQL 注 ⼊,内置 Logging 能诊断 Hack 应用行为。”
WiKi

  • 详细的监控
  • ExceptionSorter,针对主流数据的返回码都有支持
  • SQL 防注入
  • 内置加密配置
  • 众多扩展点,方便进行定制

SpringBoot 方式

引入依赖

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4	<modelVersion>4.0.0</modelVersion>
 5	<parent>
 6		<groupId>org.springframework.boot</groupId>
 7		<artifactId>spring-boot-starter-parent</artifactId>
 8		<version>2.1.1.RELEASE</version>
 9		<relativePath/> <!-- lookup parent from repository -->
10	</parent>
11	<groupId>geektime.spring.data</groupId>
12	<artifactId>druid-demo</artifactId>
13	<version>0.0.1-SNAPSHOT</version>
14	<name>druid-demo</name>
15	<description>Demo project for Spring Boot</description>
16
17	<properties>
18		<java.version>1.8</java.version>
19	</properties>
20
21	<dependencies>
22		<dependency>
23			<groupId>org.springframework.boot</groupId>
24			<artifactId>spring-boot-starter-actuator</artifactId>
25		</dependency>
26		<dependency>
27			<groupId>org.springframework.boot</groupId>
28			<artifactId>spring-boot-starter-jdbc</artifactId>
29			<!-- 需要手动排除默认的连接池 HikariCP -->
30			<exclusions>
31				<exclusion>
32					<artifactId>HikariCP</artifactId>
33					<groupId>com.zaxxer</groupId>
34				</exclusion>
35			</exclusions>
36		</dependency>
37		<dependency>
38			<groupId>org.projectlombok</groupId>
39			<artifactId>lombok</artifactId>
40		</dependency>
41
42		<dependency>
43			<groupId>com.h2database</groupId>
44			<artifactId>h2</artifactId>
45			<scope>runtime</scope>
46		</dependency>
47		<dependency>
48			<groupId>org.springframework.boot</groupId>
49			<artifactId>spring-boot-starter-test</artifactId>
50			<scope>test</scope>
51		</dependency>
52		<!-- 引入 druid-spring-boot-starter -->
53		<dependency>
54			<groupId>com.alibaba</groupId>
55			<artifactId>druid-spring-boot-starter</artifactId>
56			<version>1.1.10</version>
57		</dependency>
58	</dependencies>
59
60	<build>
61		<plugins>
62			<plugin>
63				<groupId>org.springframework.boot</groupId>
64				<artifactId>spring-boot-maven-plugin</artifactId>
65			</plugin>
66		</plugins>
67	</build>
68</project>

application.properties

 1spring.output.ansi.enabled=ALWAYS
 2
 3spring.datasource.url=jdbc:h2:mem:foo
 4spring.datasource.username=sa
 5spring.datasource.password=n/z7PyA5cvcXvs8px8FVmBVpaRyNsvJb3X7YfS38DJrIg25EbZaZGvH4aHcnc97Om0islpCAPc3MqsGvsrxVJw==
 6
 7spring.datasource.druid.initial-size=5
 8spring.datasource.druid.max-active=5
 9spring.datasource.druid.min-idle=5
10# Filter配置
11spring.datasource.druid.filters=conn,config,stat,slf4j
12
13# 密码加密
14spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=${public-key}
15spring.datasource.druid.filter.config.enabled=true
16
17spring.datasource.druid.test-on-borrow=true
18spring.datasource.druid.test-on-return=true
19spring.datasource.druid.test-while-idle=true
20
21# druid-spring-boot-starter  默认就会开启统计功能的filter  所以注释掉了
22#spring.datasource.druid.filter.stat.enabled=true
23
24# 开启慢sql日志 (默认是监控那些执行超过3秒的sql语句)
25spring.datasource.druid.filter.stat.log-slow-sql=true
26# 默认抓取超过100毫秒的sql语句
27spring.datasource.druid.filter.stat.slow-sql-millis=100
28
29public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALS8ng1XvgHrdOgm4pxrnUdt3sXtu/E8My9KzX8sXlz+mXRZQCop7NVQLne25pXHtZoDYuMh3bzoGj6v5HvvAQ8CAwEAAQ==

启动类

 1package geektime.spring.data.druiddemo;
 2
 3import lombok.extern.slf4j.Slf4j;
 4import org.springframework.beans.factory.annotation.Autowired;
 5import org.springframework.boot.CommandLineRunner;
 6import org.springframework.boot.SpringApplication;
 7import org.springframework.boot.autoconfigure.SpringBootApplication;
 8import org.springframework.jdbc.core.JdbcTemplate;
 9
10import javax.sql.DataSource;
11
12@SpringBootApplication
13@Slf4j
14public class DruidDemoApplication implements CommandLineRunner {
15	@Autowired
16	private DataSource dataSource;
17	@Autowired
18	private JdbcTemplate jdbcTemplate;
19
20	public static void main(String[] args) {
21		SpringApplication.run(DruidDemoApplication.class, args);
22	}
23
24	@Override
25	public void run(String... args) throws Exception {
26		log.info(dataSource.toString());
27	}
28}

控制台输出 发现 Connections 中包含 5 个连接

 1CreateTime:"2020-01-07 13:33:11",
 2	ActiveCount:0,
 3	PoolingCount:5,
 4	CreateCount:5,
 5	DestroyCount:0,
 6	CloseCount:0,
 7	ConnectCount:0,
 8	Connections:[
 9		{ID:1409712092, ConnectTime:"2020-01-07 13:33:11", UseCount:0, LastActiveTime:"2020-01-07 13:33:11"},
10		{ID:1083759991, ConnectTime:"2020-01-07 13:33:11", UseCount:0, LastActiveTime:"2020-01-07 13:33:11"},
11		{ID:1135523296, ConnectTime:"2020-01-07 13:33:11", UseCount:0, LastActiveTime:"2020-01-07 13:33:11"},
12		{ID:36127072, ConnectTime:"2020-01-07 13:33:11", UseCount:0, LastActiveTime:"2020-01-07 13:33:11"},
13		{ID:1698182759, ConnectTime:"2020-01-07 13:33:11", UseCount:0, LastActiveTime:"2020-01-07 13:33:11"}
14	]
15}
16
17# 如果有慢sql会显示
182020-01-08 17:36:04.426 ERROR 2004 --- [       Thread-3] c.alibaba.druid.filter.stat.StatFilter   : slow sql 209 millis. select id from foo where id = 1 for update[]

Druid Filter

  • ⽤于定制连接池操作的各种环节
  • 可以继承 FilterEventAdapter 以便 ⽅便地实现 Filter
 1package geektime.spring.data.druiddemo;
 2
 3import com.alibaba.druid.filter.FilterChain;
 4import com.alibaba.druid.filter.FilterEventAdapter;
 5import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
 6import lombok.extern.slf4j.Slf4j;
 7
 8import java.util.Properties;
 9
10@Slf4j
11public class ConnectionLogFilter extends FilterEventAdapter {
12    /**
13     * 复写的方法名字 代表 扩展点所在的位置
14     */
15    @Override
16    public void connection_connectBefore(FilterChain chain, Properties info) {
17        log.info("BEFORE CONNECTION!");
18    }
19
20    @Override
21    public void connection_connectAfter(ConnectionProxy connection) {
22        log.info("AFTER CONNECTION!");
23    }
24}
  • 修改 META-INF/druid-fifilter.properties 增加 Filter 配置
1druid.filters.conn=geektime.spring.data.druiddemo.ConnectionLogFilter

Spring 方式

引入依赖

1<dependency>  
2 <groupId>com.alibaba</groupId>  
3 <artifactId>druid</artifactId>  
4 <version>1.1.0</version>  
5 </dependency>

application.yml

 1server:  
 2 port: 8091  
 3druid:  
 4 allow:  
 5 ip: 127.0.0.1  
 6 login:  
 7 user_name: root  
 8 password: root  
 9spring:  
10 datasource:  
11 driver-class-name: com.mysql.jdbc.Driver  
12 url: jdbc:mysql://192.168.31.201:3306/shop?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false  
13 username: root  
14 password: 123456  
15 type: com.alibaba.druid.pool.DruidDataSource  
16 initial-size: 1  
17 min-idle: 1  
18 max-idle: 5  
19 max-wait-millis: 60000  
20 timeBetweenEvictionRunsMillis: 60000  
21 # 配置一个连接在池中最小生存的时间,单位是毫秒  
22 minEvictableIdleTimeMillis: 300000  
23 validationQuery: SELECT 1 FROM DUAL  
24 testWhileIdle: true  
25 testOnBorrow: true  
26 testOnReturn: false  
27 maxPoolPreparedStatementPerConnectionSize: 20  
28 # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙  
29 filters: stat,wall  
30 # 通过connectProperties属性来打开mergeSql功能;慢SQL记录  
31 connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

DruidConfig

 1package com.xdclass.couponapp.config;  
 2  
 3import com.alibaba.druid.pool.DruidDataSource;  
 4import com.alibaba.druid.support.http.StatViewServlet;  
 5import com.alibaba.druid.support.http.WebStatFilter;  
 6import org.springframework.beans.factory.annotation.Value;  
 7import org.springframework.boot.context.properties.ConfigurationProperties;  
 8import org.springframework.boot.web.servlet.FilterRegistrationBean;  
 9import org.springframework.boot.web.servlet.ServletRegistrationBean;  
10import org.springframework.context.annotation.Bean;  
11import org.springframework.context.annotation.Configuration;  
12  
13import javax.sql.DataSource;  
14import java.util.HashMap;  
15import java.util.Map;  
16  
17@Configuration  
18public class DruidConfig {  
19  
20  
21 @Value("${druid.login.user_name}")  
22 private String userName;  
23  
24 @Value("${druid.login.password}")  
25 private String password;  
26  
27 @Bean(name = "default_datadatasource")  
28 @ConfigurationProperties(prefix = "spring.datasource")  
29 public DataSource druidDataSource(){  
30 return new DruidDataSource();  
31 }  
32  
33 @Bean  
34 public ServletRegistrationBean druidServlet() {  
35 ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();  
36 servletRegistrationBean.setServlet(new StatViewServlet());  
37 servletRegistrationBean.addUrlMappings("/druid/*");  
38 Map<String, String> initParameters = new HashMap<>(3);  
39 // 用户名  
40 initParameters.put("loginUsername", userName);  
41 // 密码  
42 initParameters.put("loginPassword", password);  
43 // 禁用HTML页面上的“Reset All”功能  
44 initParameters.put("resetEnable", "false");  
45 servletRegistrationBean.setInitParameters(initParameters);  
46 return servletRegistrationBean;  
47 }  
48  
49 @Bean  
50 public FilterRegistrationBean filterRegistrationBean() {  
51 FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();  
52 filterRegistrationBean.setFilter(new WebStatFilter());  
53 filterRegistrationBean.addUrlPatterns("/*");  
54 filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");  
55 return filterRegistrationBean;  
56 }  
57}

Druid 监控台

1# http://localhost:8091/druid  
2 root  
3 root

Durid 使用注意事项

  • 没有特殊情况,不要在生产环境打开监控的 Servlet,负载情况以日志输出为基准。
  • 没有连接泄漏可能的情况下,不要开启 removeAbandoned。(大量和使用 ORM 框架的情况下。)
  • testXxx 的使用需要注意,性能开销比较大。
  • 务必配置合理的超时时间。

作者:Soulboy