druid配置项详解

源码地址

GitHub - alibaba/druid: 阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池

druid常用配置

# 创建DB连接4要素
spring.datasource.druid.url=xxx
spring.datasource.druid.username=xxx
spring.datasource.druid.password=xxx
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver

# 在数据库连接池首次创建的时候初始化几个连接
spring.datasource.druid.initial-size=5
# 最多可以激活的连接个数
spring.datasource.druid.max-active=10
# 最小的数据库空闲连接个数
spring.datasource.druid.min-idle=5
# 创建连接时的最大等待时长,一般这个不在意
spring.datasource.druid.max-wait=60000
# 当执行数据库连接存活检查时,使用的通信sql语句
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
# 是不是在每次获取连接的时候都进行检查,设置为fale,对性能影响高
spring.datasource.druid.test-on-borrow=false
# 是不是在每次归还(事务执行结束)连接的时候检查,对性能影响高
spring.datasource.druid.test-on-return=false
# 是否在连接空闲的时候sql检查连接(这个参数只有在获取连接的时候才会使用)
spring.datasource.druid.test-while-idle=true
# 在销毁线程中表示的是执行的时间间隔
# 在获取连接的时候,配合test-while-idle=true使用
# 表示的最小的空闲时间,大于这个时间才会进行sql检查连接
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 最小的连接空闲时间,小于这个时间不会进行回收
spring.datasource.druid.min-evictable-idle-time-millis=3600000
# 是否开启会话保持,开启了之后如果在销毁的时候低于minidle的数量才会补充
spring.datasource.druid.keep-alive=true
# 开启了会话保持之后,对于不回收的连接
# 多长时间进行validateQuery一次校验,校验失败的话,还需要关闭异常链接并新建
spring.datasource.druid.keep-alive-between-time-millis=3600000

mysql进行jdbc连接

import java.sql.*;

public class JdbcDemo {
    public static void main(String[] args) {
        try {
            // 加载MySQL驱动程序
            Class.forName("com.mysql.jdbc.Driver");
            // 建立与MySQL的连接
            String url = "jdbc:mysql://localhost:3306/test";
            String user = "root";
            String password = "123456";
            Connection conn = DriverManager.getConnection(url, user, password);
            // 创建Statement对象
            Statement stmt = conn.createStatement();
            // 执行查询操作
            String sql = "SELECT * FROM users WHERE age > 18";
            ResultSet rs = stmt.executeQuery(sql);
            // 处理查询结果
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                System.out.println("id=" + id + ", name=" + name + ", age=" + age);
            }
            // 关闭资源
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException
         e) {
            e.printStackTrace();
        }
    }
}

druid各配置项生效原理

初始化过程

com.alibaba.druid.pool.DruidDataSource#init

this.connections = new DruidConnectionHolder[this.maxActive];
this.evictConnections = new DruidConnectionHolder[this.maxActive];
this.keepAliveConnections = new DruidConnectionHolder[this.maxActive];

while(this.poolingCount < this.initialSize) {
    try {
        DruidAbstractDataSource.PhysicalConnectionInfo pyConnectInfo = this.createPhysicalConnection();
        DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
        this.connections[this.poolingCount++] = holder;
    } catch (SQLException var18) {
        LOG.error("init datasource error, url: " + this.getUrl(), var18);
        if (this.initExceptionThrow) {
            connectError = var18;
            break;
        }

        Thread.sleep(3000L);
    }
}

上面是连接池的初始化过程,数组长度是maxActive, 代表最多能拥有的连接个数,同时分为三个数组存放。

然后循环初始化数据库连接,保存至数据中,初始化的个数是initialSize个

线程任务

连接创建线程

通过信号量等控制线程运行,从而保持线程池数量。这个先不管

com.alibaba.druid.pool.DruidDataSource.CreateConnectionThread#run

连接销毁线程

com.alibaba.druid.pool.DruidDataSource.DestroyConnectionThread#run

while(true) {
    try {
        if (DruidDataSource.this.closed || DruidDataSource.this.closing) {
            break;
        }

        if (DruidDataSource.this.timeBetweenEvictionRunsMillis > 0L) {
            Thread.sleep(DruidDataSource.this.timeBetweenEvictionRunsMillis);
        } else {
            Thread.sleep(1000L);
        }

        if (Thread.interrupted()) {
            break;
        }

        DruidDataSource.this.destroyTask.run();
    } catch (InterruptedException var2) {
        break;
    }
}

timeBetweenEvictionRunsMillis:这个参数是标识这个线程需要sleep多久之后才能唤醒下一次销毁执行

com.alibaba.druid.pool.DruidDataSource.DestroyTask#run

// 连接池的空闲数量 去除 最小保留的空闲连接
checkCount = this.poolingCount - this.minIdle;

// 记录空闲时长
idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
// 如果空闲时长 大于最小空闲时间 并且在保留的最小空闲连接之外则移除
if (idleMillis >= this.minEvictableIdleTimeMillis) {
    if (checkTime && i < checkCount) {
        this.evictConnections[evictCount++] = connection;
        continue;
    }

    // 如果空闲时间比最大的空闲时间还大,则直接移除
    if (idleMillis > this.maxEvictableIdleTimeMillis) {
        this.evictConnections[evictCount++] = connection;
        continue;
    }
}

minEvictableIdleTimeMillis:空闲连接的最小保留时长,低于这个时间不会回收。高于这个时间,则移除比minIdle多出数量的连接。

maxEvictableIdleTimeMillis:默认7个小时,不管个数,空闲时间达到即移除。

通过keepalive参数进行保活
// 这个是不满足驱逐逻辑之后才执行的
// 如果设置了保持存活,且连接的空闲时间大于应该保持存活的时间了
if (keepAlive && idleMillis >= this.keepAliveBetweenTimeMillis) {
    this.keepAliveConnections[keepAliveCount++] = connection;
}

// 需要保活,且数量低于最小空闲连接,则需要补充,就是通过唤起创建线程补充
if (keepAlive && this.poolingCount + this.activeCount < this.minIdle) {
    needFill = true;
}

keepAlive:是否需要保持连接存活

keepAliveBetweenTimeMillis:多久进行一次保活。

keepAliveConnections:有需要保活的连接,则利用validationQuery进行保活。保活失败,则重新创建连接,依赖于上述两个配置。

needFill:如果需要补充连接的话,也会重新创建连接。依赖于keepAlive以及连接数量情况。

获取连接过程

com.alibaba.druid.pool.DruidDataSource#getConnectionDirect

// testOnBorrow 参数的使用
if (this.testOnBorrow) {
    // 如果
    boolean validate = this.testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
    if (validate) {
        break;
    }

    if (LOG.isDebugEnabled()) {
        LOG.debug("skip not validate connection.");
    }

    this.discardConnection(poolableConnection.holder);
}

// testWhileIdle参数的使用
if (!this.testWhileIdle) {
    break;
}

long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;

// 只有空闲时间大于timeBetweenEvictionRunsMillis 这个时间,才会进行验证
if (idleMillis < timeBetweenEvictionRunsMillis && idleMillis >= 0L) {
    break;
}

// 验证失败就会丢弃连接
boolean validate = this.testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
if (validate) {
    break;
}

this.discardConnection(poolableConnection.holder);

testOnBorrow:获取连接的时候进行检测

testWhileIdle:获取连接的时候,且其空闲时间大于timeBetweenEvictionRunsMillis开始进行检测

Druid连接池是一个开源的、高效的数据库连接池,适用于Java应用程序。它能够提供连接池和管理连接的功能,帮助进行数据库连接的管理和优化。 Druid连接池的配置主要包括以下几个方面: 1. 数据源配置:可以通过配置文件或代码来设置数据库相关的属性,如驱动类型、URL、用户名、密码等。这些配置可以根据具体的数据库类型和环境需求来设置。 2. 连接池参数配置:可以设置连接池的一些基本参数,如初始化连接数、最小连接数、最大连接数等。这些参数会直接影响连接池的性能和资源占用情况,需要根据具体应用的需求进行调整。 3. 连接属性配置:可以设置每个连接的一些属性,如连接超时时间、最大等待时间、是否自动提交等。这些属性可以根据具体需求进行设置,以满足应用程序的要求。 4. 监控配置:可以设置连接池的监控功能,包括连接池的活跃连接数、空闲连接数、执行SQL次数、慢查询次数等。这些监控数据可以通过配置输出到日志文件或通过JMX暴露出来,以便进行监控和调优。 5. 连接池扩展配置:可以通过配置来设置连接池的一些扩展功能,如连接池的预处理、过滤器等。这些功能可以提供更灵活的连接管理方式,以满足特定需求。 通过合理配置Druid连接池,可以提高应用程序对数据库连接的管理和利用效率,减少连接泄露和性能问题。但是需要注意的是,配置应遵循最佳实践,并根据实际情况进行调整和优化,以达到最佳的数据库连接池配置效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值