一. 为什么要使用数据库连接池?
1.1 不使用数据库连接池:
对于并发量大的网站,会导致以下问题:
- 每一次web请求都要建立一次数据库连接,在同样的步骤下**
重复占用系统资源
** - 不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,连接过多情况下可能导致
**内存泄漏,服务器崩溃**
。
1.2 使用数据库连接池:
提高性能
,将已经创建好的连接保存在连接池中,当有请求来时,直接从连接池中使用已经创建好的连接进行数据库服务器的访问。省略了创建连接和销毁连接的过程
,TCP连接建立时的三次握手和销毁时的四次握手。
1.3 选择用什么数据源?
Spring boot 1.x版本
如果不配置数据源默认会使用Tomcat数据源
DataSource`,- 而在
Spring boot2.x默认的数据库连接池由Tomcat换成了HikariCP
。HiKariCP是数据库连接池的一个后起之秀,号称性能最好,可以完美地PK掉其他连接池,是一个高性能的JDBC连接池,但这里我们选择国内主流数据源阿里巴巴的Druid(德鲁伊),因为它有配套数据源、数据监控、安全的解决方案。
二.整合Druid
- 加入Druid的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- 配置数据库连接池
Druid必须的配置其实很少,只需配置type指定为Druid,表明不使用默认的HikariCP。参数调优部分是可选的,这里列出的参数都是druid官网推荐的典型配置。
application.properties:
# druid配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# druid参数调优(可选)
# 初始化大小,最小,最大
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=20
# 配置获取连接等待超时的时间
spring.datasource.druid.max-wait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.druid.min-evictable-idle-time-millis=300000
# 测试连接
spring.datasource.druid.validation-query=select 'x'
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
# 配置监控统计拦截的filters
spring.datasource.druid.filters=stat
# asyncInit是1.1.4中新增加的配置,如果有initialSize数量较多时,打开会加快应用启动时间
spring.datasource.druid.async-init=true
application.yml
spring:
thymeleaf:
cache: false
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/bookseshop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password:
#初始化大小,最小,最大
initial-size: 5
min-idle: 5
max-active: 20
#连接等待超时时间
max-wait: 30000
#配置检测可以关闭的空闲连接间隔时间
time-between-eviction-runs-millis: 60000
#配置连接在池中的最小生存时间
min-evictable-idle-time-millis: 300000
#用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
validation-query: select 'X'
#申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
test-while-idle: true
#归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
test-on-borrow: false
#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-on-return: false
#是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
pool-prepared-statements: false
max-open-prepared-statements: 20
#要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
max-pool-prepared-statement-per-connection-size: 20
#Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔
aop-patterns: com.xj.demo.servie.*
#合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
#配置监控统计拦截的filters
filter:
#监控统计用的filter:stat
stat:
enabled: true
merge-sql: true
log-slow-sql: true
#配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢
slow-sql-millis: 5000
#防御sql注入的filter:wall
wall:
enabled: true
config:
#是否允许执行DELETE语句
delete-allow: true
#是否允许修改表
drop-table-allow: true
slf4j:
enabled: true
statement-executable-sql-log-enable: true
#所有Statement相关的日志
statement-log-enabled: false
- junit测试是否切换数据源成功
@Autowired
private DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
- Controller测试是否整合成功
@RequestMapping("/testDruid")
public String testDruid() {
String sql = "SELECT * from t_book";
String str = "";
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = dataSource.getConnection().prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()){
str = rs.getString(2);
System.out.println(str);
}
} catch (SQLException e) {
e.printStackTrace();
}
return "index";
}
三.配置Druid监控
方式2:
用配置类的方式进行配置,例如:
/**
* @Description: Druid配置类
* @Author: x1c
* @Date:
*/
@Configuration
public class DruidConfig {
private static final Logger logger = LoggerFactory.getLogger(DruidConfig.class);
@Bean
public ServletRegistrationBean<StatViewServlet> druidServlet() {
logger.info("--------------init Druid Servlet DruidConfig--------------");
ServletRegistrationBean<StatViewServlet> srBean = new ServletRegistrationBean<>();
srBean.setServlet(new StatViewServlet());
srBean.addUrlMappings("/druid/*");
// IP白名单
srBean.addInitParameter("allow", "127.0.0.1");
// IP黑名单(共同存在时,deny优先于allow)
//srBean.addInitParameter("deny", "192.168.1.100");
//控制台管理用户
srBean.addInitParameter("loginUsername", "admin");
srBean.addInitParameter("loginPassword", "admin");
//是否能够重置数据 禁用HTML页面上的“Reset All”功能
srBean.addInitParameter("resetEnable", "false");
return srBean;
}
@Bean
public FilterRegistrationBean<WebStatFilter> filterRegistrationBean() {
FilterRegistrationBean<WebStatFilter> filterBean = new FilterRegistrationBean<>(new WebStatFilter());
filterBean.addUrlPatterns("/*");
Map<String, String> initParams = new HashMap<String, String>();
initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");
filterBean.setInitParameters(initParams);
return filterBean;
}
}
启动项目,访问:http://localhost:8080/druid/login.html 进行测试