赞
踩
DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池。
(1)DataSource中URL重要配置参数(Spring配置前缀:spring.datasource.url)
| 配置 | 缺省值 | 说明 | 推荐说明 |
| serverTimezone | 时区 | Asia/Shanghai | |
| useUnicode | true | ||
| characterEncoding | 1、存数据 数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码,并存放到数据库中。 2、取数据 在数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端 | UTF8 | |
| useSSL | true | MySQL在高版本需要指明是否进行SSL连接 | false |
(2)Druid重要配置参数(Spring配置前缀:spring.datasource.druid)
| 配置 | 缺省值 | 描述 | 推荐说明 |
| initial-size | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 | 连接数=(核心数 * 2) + 有效磁盘数) |
| min-idle | 最小连接池数量 | 与initialSize一致 | |
| max-idle | 8 | 最大连接池数量 | |
| max-wait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁 | ||
| use-unfair-lock | false | 如果设置了maxWait,则启用公平锁 | |
| time-between-eviction-runs-millis | 60000 | 在空闲连接回收器线程运行期间休眠时间,它决定线程多久验证空闲连接或丢弃连接的频率 | 源码上看,是通过validation-query配置的语句语句检测连接的有效性,如果连接失败了则丢弃 |
| min-evictableIdle-time-millis | 1800000 | 连接在池中保持空闲而不被回收的最小时间 | |
| validation-query | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用false | 如果检测到已知驱动后,会使用MySqlValidConnectionChecker类进行有效检测,走的是ping策略,而不是该配置,哪怕没有配置也会走默认的 “select 1”,前提是使用MySqlValidConnectionChecker,不然是直接返回true的 | |
| validation-query-timeout | -1 | 检测连接超时时间 | 虽然这里默认是-1,但是实际代码会设置成1s的时间 |
| test-on-borrow | false | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 | |
| test-while-idle | true | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效 | |
| test-on-return | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 | |
| pool-prepared-statements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭 | |
| max-open-prepared-statements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 | |
| filter-class-names | |||
| flter.stat.slow-sql-millis |
- spring:
- datasource:
- url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&useSSL=false
- username: root
- password: root
- driver-class-name: com.mysql.cj.jdbc.Driver
以数据库实例是4核8G为例(待考量):
- spring:
- datasource:
- druid:
- initial-size: 10
- min-idle: 10
- max-active: 25
- max-wait: 60000
- use-unfair-lock: true
- time-between-eviction-runs-millis: 60000
- min-evictable-idle-time-millis: 300000
设置后,性能会翻倍(见参考资料有赞优化),但是这样做有没有其他问题?
(1) com.alibaba.druid.pool.DruidDataSource#getConnectionDirect
- public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
- int notFullTimeoutRetryCnt = 0;
- for (;;) {
- // ...
-
- if (testOnBorrow) {
- // ...
- } else {
- if (poolableConnection.conn.isClosed()) {
- discardConnection(poolableConnection.holder); // 传入null,避免重复关闭
- continue;
- }
-
- if (testWhileIdle) {
- final DruidConnectionHolder holder = poolableConnection.holder;
- long currentTimeMillis = System.currentTimeMillis();
- long lastActiveTimeMillis = holder.lastActiveTimeMillis;
- long lastExecTimeMillis = holder.lastExecTimeMillis;
- long lastKeepTimeMillis = holder.lastKeepTimeMillis;
-
- if (checkExecuteTime
- && lastExecTimeMillis != lastActiveTimeMillis) {
- lastActiveTimeMillis = lastExecTimeMillis;
- }
-
- if (lastKeepTimeMillis > lastActiveTimeMillis) {
- lastActiveTimeMillis = lastKeepTimeMillis;
- }
-
- long idleMillis = currentTimeMillis - lastActiveTimeMillis;
-
- long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;
-
- if (timeBetweenEvictionRunsMillis <= 0) {
- timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
- }
- // 如果空闲时间达到阙值
- if (idleMillis >= timeBetweenEvictionRunsMillis
- || idleMillis < 0 // unexcepted branch
- ) {
- // 检测连接是否有效
- boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
- if (!validate) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("skip not validate connection.");
- }
- // 无效则关闭连接
- discardConnection(poolableConnection.holder);
- continue;
- }
- }
- }
- }
-
- // ...
- }

(2) 关闭连接后,如果当前存活数小于最小连接数
空信号的处理利用的是AQS的Condition.sign(),这里还不确定会不会开启。Condition忘记了~
- public void discardConnection(DruidConnectionHolder holder) {
- if (holder == null) {
- return;
- }
-
- Connection conn = holder.getConnection();
- if (conn != null) {
- JdbcUtils.close(conn);
- }
-
- lock.lock();
- try {
- if (holder.discard) {
- return;
- }
-
- if (holder.active) {
- activeCount--;
- holder.active = false;
- }
- discardCount++;
-
- holder.discard = true;
-
- if (activeCount <= minIdle) {
- emptySignal();
- }
- } finally {
- lock.unlock();
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。