Mysql-Druid连接池配置

1. 背景

DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池。

2. 介绍

(1)DataSource中URL重要配置参数(Spring配置前缀:spring.datasource.url)

配置缺省值说明推荐说明
serverTimezone 时区Asia/Shanghai
useUnicode  true
characterEncoding 

1、存数据

数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码,并存放到数据库中。

2、取数据

在数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端

UTF8
useSSLtrueMySQL在高版本需要指明是否进行SSL连接false

(2)Druid重要配置参数(Spring配置前缀:spring.datasource.druid)

配置缺省值描述推荐说明
initial-size0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时连接数=(核心数 * 2) + 有效磁盘数)
min-idle 最小连接池数量与initialSize一致
max-idle8最大连接池数量 
max-wait 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁 
use-unfair-lockfalse如果设置了maxWait,则启用公平锁 
time-between-eviction-runs-millis60000在空闲连接回收器线程运行期间休眠时间,它决定线程多久验证空闲连接或丢弃连接的频率源码上看,是通过validation-query配置的语句语句检测连接的有效性,如果连接失败了则丢弃
min-evictableIdle-time-millis1800000连接在池中保持空闲而不被回收的最小时间 
validation-query 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用false如果检测到已知驱动后,会使用MySqlValidConnectionChecker类进行有效检测,走的是ping策略,而不是该配置,哪怕没有配置也会走默认的 “select 1”,前提是使用MySqlValidConnectionChecker,不然是直接返回true的
validation-query-timeout-1检测连接超时时间虽然这里默认是-1,但是实际代码会设置成1s的时间
test-on-borrowfalse申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 
test-while-idletrue建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效 
test-on-returnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 
pool-prepared-statementsfalse是否缓存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   

3. 源码

 

4. 实战

4.1 数据库连接配置

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.2 Druid配置

以数据库实例是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

5. FAQ

5.1 Druid是否有必要在设置了maxWait后,还要强制设置useUnfairLock=true?

设置后,性能会翻倍(见参考资料有赞优化),但是这样做有没有其他问题?

5.2  检测到连接达空闲时间上线时,Druid会物理关闭该连接,那么它不保证最小连接数吗?会重新开启新的连接吗?

(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();
        }
    }

 

6. 参考资料

有赞DB连接池性能优化

数据库连接池的大小配置

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于简化Spring应用开发的框架,而Druid是一个高效的数据库连接池。在Spring Boot项目中使用Druid连接池可以提供高性能的数据库连接管理和监控功能。 要在Spring Boot中使用Druid连接池,需要以下步骤: 1. 在项目的pom.xml文件中添加Druid依赖: ```xml <dependencies> <!-- Spring Boot Starter JDBC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- Druid依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> </dependencies> ``` 2. 在application.properties或application.yml文件中配置Druid连接池相关属性,例如: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver # 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 1 spring.datasource.druid.test-while-idle=true spring.datasource.druid.test-on-borrow=false spring.datasource.druid.test-on-return=false spring.datasource.druid.filters=stat spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20 spring.datasource.druid.use-global-data-source-stat=true ``` 3. 在启动类上添加`@EnableTransactionManagement`和`@MapperScan`注解,例如: ```java @SpringBootApplication @EnableTransactionManagement @MapperScan("com.example.mapper") public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 以上是在Spring Boot项目中使用Druid连接池的基本配置步骤,你可以根据自己的需求修改配置参数来满足具体业务场景。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值