Druid源码分析(五)-- 连接池

  • Druid源码分析(五)-- 连接池
  • 连接池
  • 总结


Druid源码分析(五)-- 连接池

连接池

我们可以看到 druid-spring-boot-starter 的配置是初始化连接2个,连接池最大数量是30,最小数量是2个

# Druid 数据源配置,继承spring.datasource.* 配置,相同则覆盖
spring.datasource.druid.initial-size=2
spring.datasource.druid.max-active=30
spring.datasource.druid.min-idle=2

然后这边默认是同步初始化

private boolean asyncInit  = false;

当然我们可以在配置文件加上这行配置,改为异步初始化

spring.datasource.druid.async-init=true

前面 init 函数里有一段代码,同步初始化的时候,会循环创建配置的初始化数量的连接

while (poolingCount < initialSize) {
    try {
    	// 创建连接
        PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
        // 把连接包装成DruidConnectionHolder 
        DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
        // 把连接加入连接池
        connections[poolingCount++] = holder;
    } catch (SQLException ex) {
       ...
    }
}

debug可以看到,配置是没问题的,然后这边会循环2次创建连接conn,加入到连接池

druid连接池mysql sleep线程过多如何解决 druid连接池数量_mysql


我们接着往里看,这边是先创建物理数据库连接,然后再包装成DruidConnectionHolder ,加入到连接池

// DruidAbstractDataSource.java
public PhysicalConnectionInfo createPhysicalConnection() throws SQLException {
	...
 	conn = createPhysicalConnection(url, physicalConnectProperties);

这里又调用了另一个函数来创建连接

// DruidAbstractDataSource.java
public Connection createPhysicalConnection(String url, Properties info) throws SQLException {
    Object conn;
    // 这里判断有没有filter,如果没有,直接通过驱动创建连接,有的话,需要通过责任链的形式创建连接
    if (this.getProxyFilters().size() == 0) {
        conn = this.getDriver().connect(url, info);
    } else {
        conn = (new FilterChainImpl(this)).connection_connect(info);
    }

    createCountUpdater.incrementAndGet(this);
    return (Connection)conn;
}

因为我们这边配置开启了statFilter,所以走的是下面的责任链模式创建连接

spring.datasource.druid.filter.stat.db-type=h2
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=2000

druid连接池mysql sleep线程过多如何解决 druid连接池数量_java_02


不过里面最终还是用数据库驱动去获取的连接conn

// FilterChainImpl.java
public ConnectionProxy connection_connect(Properties info) throws SQLException {
    if (this.pos < this.filterSize) {
     	// 责任链模式循环filter
        return this.nextFilter().connection_connect(this, info);
    } else {
        Driver driver = this.dataSource.getRawDriver();
        String url = this.dataSource.getRawJdbcUrl();
        // 通过驱动获取连接
        Connection nativeConnection = driver.connect(url, info);
        return nativeConnection == null ? null : new ConnectionProxyImpl(this.dataSource, nativeConnection, info, this.dataSource.createConnectionId());
    }
}

创建物理数据库连接后,就是把连接包装成DruidConnectionHolder ,设置数据源、连接、连接创建时间、连接时间、是否自动提交等

// DruidConnectionHolder.java
this.dataSource = dataSource;
this.conn = conn;
this.createNanoSpan = connectNanoSpan;

this.connectTimeMillis = System.currentTimeMillis();
this.lastActiveTimeMillis = connectTimeMillis;
this.lastExecTimeMillis   = connectTimeMillis;
this.underlyingAutoCommit = conn.getAutoCommit();
...

最后连接池里就有了2个连接

druid连接池mysql sleep线程过多如何解决 druid连接池数量_连接池_03

总结

Druid连接池里存的是包装过后扩展了很多参数的连接conn ,这些连接最终还是通过数据库驱动来创建的,然后这边的filter用到了责任链模式,和shenyu项目是很像的,如果我们写项目,支持用户自定义filter,也可以用责任链模式。