目录
一、数据库连接数基本知识
1.查看默认连接数
2.修改默认连接数
3.查看数据库当前连接数
二、jmeter压测数据库
三、druid连接池
1.连接池配置
2.查看配置是否生效
一、数据库连接数基本知识
1.查看默认连接数
mysql默认最大连接数最大值为:151
语句:
show variables like '%connections%';
show variables like '%max_connections%';
2.修改默认连接数
语句:set GLOBAL max_connections=50;
修改mysql默认连接数,然后查看如下:
3.查看数据库当前连接数
查看当前和数据库建立的连接数:
语句:show status like 'Threads%';
- Threads_cached:线程缓存内的线程数量
- Threads_connected:当前打开的连接数量, Threads_connected 跟show processlist结果相同
- Threads_created:创建的线程数
- Threads_running:正在运行的线程数(激活的连接数),这个数值一般远低于connected数值;准确的来说, Threads_running是代表当前并发数
执行命令如下:
show PROCESSLIST;
总共46条记录,其中一条状态为starting的就是当前执行的这条语句
通过show status like 'Threads%';语句也看到,刚好是46个连接,和show PROCESSLIST;显示的数量一致。
另一个解释:
三个参数,一个是treads_cached这个是缓冲池中的线程个数。还有一个是treads_connected这个是连接中的线程数。第三个是Threads_created,它的含义是已经创建的线程数。在并发数低的情况下,一般Threads_created参数是treads_cached和treads_connected参数之和。当并发数高的情况下,Threads_created就会暴增,这个时候就需要考虑thread_cache_size来设置缓冲池的大小了。
二、jmeter压测数据库
先把最大连接数改小一点,方便连接数达到峰值,这里改为50。
jmeter如下:500个线程,每个线程循环50次:
如下,请求获取用户列表的接口,即数据库一直在执行查询操作
启动,此时一直查询,然后查看数据库连接数如下:已经51了,此时就满了,不管发多少个请求数据库连接数都不会再增加 了
并且jmeter一直发请求,导致连接数过多,后端代码会报错,如下:
提示连接数过多:Too many connections
java.sql.SQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110) ~[mysql-connector-java-8.0.30.jar:8.0.30]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-java-8.0.30.jar:8.0.30]
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:828) ~[mysql-connector-java-8.0.30.jar:8.0.30]
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:448) ~[mysql-connector-java-8.0.30.jar:8.0.30]
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:241) ~[mysql-connector-java-8.0.30.jar:8.0.30]
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198) ~[mysql-connector-java-8.0.30.jar:8.0.30]
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1678) ~[druid-1.2.12.jar:1.2.12]
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1755) ~[druid-1.2.12.jar:1.2.12]
at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2825) ~[druid-1.2.12.jar:1.2.12]
直接查询数据库时也无法查询了 ,提示连接数过多,因为打开Navicat执行一次查询语句,也是一个连接数。
修改连接数也不行,因为执行修改语句也要占用一个连接
此时需要等待连接数释放,或者重启数据库服务器。等待连接数释放还有一种方案,就是把链接数据库的服务器停掉,比如后端的一个springboot服务连接的数据库连接数满了,直接把springboot服务停止调,让别人无法通过该服务连接数据库,等一会儿,等待连接数失效释放即可。
我把springboot服务停止十几分钟,执行如下两条查询语句都不行,仍然提示连接数满了
重启springboot服务提示满了
这是为啥呢?过了十几分钟仍然没有释放连接。暂时猜测是最大空闲时间太长,导致连接十几分钟后还没有释放,先重启mysql服务,如下,我是用docker容器启动的:
再次查询sql:
已经正常查询如下:并且连接数为1,创建的线程为1,正在执行的线程也是1,这个1就是当前执行的这条语句
查询一个表也正常了:
再次查看,连接数和创建的线程就是2了,因为上一条加这一条就是两条连接了:
三、druid连接池
1.连接池配置
# mysql数据源
spring:
# 允许循环依赖 暂时这么解决 后面抽时间再处理
main:
allow-circular-references: true
#easypoi 自动配置类和springboot自动配置类bean冲突解决
allow-bean-definition-overriding: true
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://113.250.xxx.xxx:3306/environment?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=true
username: xxxx
password: xxxx
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 5
min-idle: 5 #最小连接池数量
max-active: 20 #最大连接池数量
max-wait: 6000 #获取连接时最大等待时间,单位毫秒
min-evictable-idle-time-millis: 600000 #配置一个连接在池中最小生存的时间,单位是毫秒 10分钟
max-evictable-idle-time-millis: 900000 #配置一个连接在池中最大生存的时间,单位是毫秒 15分钟
time-between-eviction-runs-millis: 6000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
test-while-idle: true #如果为true(默认true),当应用向连接池申请连接,并且testOnBorrow为false时,连接池将会判断连接是否处于空闲状态,如果是,则验证这条连接是否可用
test-on-borrow: false #验证连接,配合test-while-idle使用
test-on-return: false #当应用使用完连接,连接池回收连接的时候会判断该连接是否还可用
可以参考阿里巴巴给的通用配置:
DruidDataSource配置 · alibaba/druid Wiki · GitHub
2.查看配置是否生效
写一个测试类,打断点看看dataSource类,查看数据源配置的东西是否都确实生效了。
package com.tn.humanenv;
import com.alibaba.fastjson.JSON;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import javax.sql.DataSource;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MonsterlanApplicationTests {
@Autowired
DataSourceProperties dataSourceProperties;
@Autowired
ApplicationContext applicationContext;
/*也可以直接依赖DataSource*/
@Autowired
DataSource dataSource1;
@Test
public void contextLoads() {
// 获取配置的数据源
DataSource dataSource = applicationContext.getBean(DataSource.class);
// 查看配置数据源信息
System.out.println(dataSource);
System.out.println(dataSource.getClass().getName());
System.out.println(dataSourceProperties);
System.out.println(dataSource.getClass());
System.out.println(dataSource.getClass().getName());
//执行SQL,输出查到的数据
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List<?> resultList = jdbcTemplate.queryForList("select * from sys_user");
System.out.println("===>>>>>>>>>>>" + JSON.toJSONString(resultList));
}
}