项目实训1
1. 背景
建立数据库连接耗时耗费资源,一个数据库服务器能够同时建立的连接数也是有限的,在大型的Web应用中,可能同时会有成百上千的访问数据库的请求,如果Web应用程序为每一个客户请求分配一个数据库连接,将导致性能的急剧下降。
数据库连接池的意义在于,能够重复利用数据库连接(有点类似线程池的部分意义),提高对请求的响应时间和服务器的性能。
连接池中提前预先建立了多个数据库连接对象,然后将连接对象保存到连接池中,当客户请求到来时,直接从池中取出一个连接对象为客户服务,当请求完成之后,客户程序调用close()方法,将连接对象放回池中。
当用户量急剧增加,同时对数据库的访问也会急剧增加,为了提高
请求的响应时间和服务器的性能,故在本项目中集成数据源。
2. druid介绍及作用:
druid为阿里巴巴的数据源,(数据库连接池),集合了c3p0、dbcp、proxool等连接池的优点,还加入了日志监控,有效的监控DB池连接和SQL的执行情况。
数据源的介绍:
数据源(DataSource)
制SUN制定的用于获取数据库连接的规范接口。
它存在于 javax.sql包中,用来代替 DriverManager 的方式
来获取连接。
DataSource 与 DriverManager 获取连接的不同:
DriverManager是由SUN实现的,它只供了最基本的获取
连接的方式。
而DataSource是一个接口,不光SUN可以实现,很多第三方
的中间件也可以实现,而且实现得很好。
DataSource一般有如下三种实现方式:
标准实现 – 提供最基本的连接,也就是DriverManager的方式
连接池的实现 – 提供了连接池,是一种可以缓存及管理多个
数据库连接的“容器”。
分布事务的实现 – 提供了连接池,而且这个池中的连接是
支持分布式事务的(Distribute Transaction)
一般来说,DataSource 都会由专业的中间件(MiddleWare)来实现。
当然,也有一些开源(免费)的 DataSource的实现。
最有名就是:Apache 组织提供的 commons-dbcp
3. 项目中集成
- 首先在maven中添加依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid 数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<!-- druid 监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 配置数据源
# druid数据源
spring.datasource.druid.url=xxxxxxxxxxx
spring.datasource.druid.username=xxxx
spring.datasource.druid.password=xxxxxxxxxxxxx
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
- 配置Druid的连接池
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
在配置中,指定了初始化时建立物理连接的个数为10。初始化发生在显示调用init方法,或者第一次getConnection时;最大连接池数量为8;最小连接池数量minIdle为1; 获取连接时最大等待时间60000,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
以下是相关配置具体解释:
配置 | 缺省值 | 说明 |
---|---|---|
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,是组合关系,并非替换关系 |
- 配置数据库监控
# 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
4. 效果展示
启动项目
可以发现数据源已经被初始化。
使用postman测试
//登录
@PostMapping("/login")
public Object login(User user){
User userForBase=userService.findUserByPhoneNumber(user.getPhoneNumber());
if(userForBase==null){
throw new CustomException(ResultCodeEnum.UNKNOWN_USER);
}else {
if (!userForBase.getPassword().equals(user.getPassword())){
throw new CustomException(-10,"登录失败,密码错误");
}else {
String token = jwtUitls.getToken(userForBase);
return ResultFactory.success().message(token); //返回含有token的result
}
}
}
我们可以看到在项目启动时先执行了sql脚本初始化,也就是上图的第二条SQL,之后,调用login接口登录,从数据库中查找了用户信息,也就是上图的第1条SQL。
至此,对于druid的简单配置及使用已经完成。