Простой анализ инициализации пула соединений Druid (1)

Java
Простой анализ инициализации пула соединений Druid (1)
WeChat поискJava-база, учитесь вместе и прогрессируйте вместе!

Знакомство с Друидом:

Появление пула соединений решает проблему потребления производительности программы при создании соединения с базой данных для каждого запроса в сценариях с высокой степенью параллелизма и увеличения времени ответа на запрос. Раньше я использовал пул соединений C3P0, а затем обратил внимание на пул соединений Druid, пул соединений с базой данных, созданный подразделением баз данных Alibaba, известный как пул соединений с базой данных, созданный мониторингом. По сравнению с другими пулами соединений он обеспечивает богатый многомерный мониторинг данных.

Адрес источника Druid git:GitHub.com/alibaba/import…


Инициализация друида:

Обычно используемое описание существительного-атрибута:

url                            :数据库地址,通过前缀指定驱动类型。
username                       :数据库用户名
password                       :数据库密码
initialSize                    :连接池初始化大小
maxActive                      :连接池最大连接数
maxWait                        :获取连接最大等待时间
testOnBorrow                   :获取连接时是否检测连接是否有效
testOnReturn                   :回收连接时是否检测连接是否有效
testWhileIdle                  :获取连接时是否检测连接连接空闲时间超过
                                 timeBetweenEvictionRunsMillis,超过则检测连接
timeBetweenEvictionRunsMillis  :DestroyConnectionThread线程(定时检测连接有效性)
                                 执行间隔(Sleep控制)
minEvictableIdleTimeMillis     :连接再线程池中最小存活时间
removeAbandoned                :是否开启线程活动时间超过removeAbandonedTimeout,进行丢弃
removeAbandonedTimeout         :活动线程最大存活时间,超过直接丢弃(单位分钟)。
logAbandoned                   :关闭abandon连接是否打印日志。
filters                        :需要启用Druid的过滤器。
connectionInitSqls             :连接时需要设置的mysql参数,例:set names utf8mb4;asyncInit                      :是否异步初始化连接池
createScheduler                :初始化连接的线程池
validationQuery                :创建连接校验连接是否有效执行的sql语句
keepAlive                      :是否创建空闲连接
minIdle                        :最小空闲连接数

Источники данных можно настроить в Spring иАтрибут init-method напрямую вызывает метод init.

<bean name="readDataSource1" class="com.alibaba.druid.pool.DruidDataSource"  
 init-method="init" destroy-method="close">

Если инициализация не вызывается вручную, логика инициализации также будет запущена для завершения инициализации при первом вызове метода getConnection DataSource.

public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
    init();    
    if (filters.size() > 0) {        
        FilterChainImpl filterChain = new FilterChainImpl(this);
        return filterChain.dataSource_connect(this, maxWaitMillis);
    } else {
            return getConnectionDirect(maxWaitMillis);
    }
}

Инициализация DruidDataSource обычно делает несколько вещей:

1. Обработка значений пользовательских параметров. Определяем тип БД (Mysql или Oracle) по jdbcUrl, проверяем корректность параметров, инициализируем настроенный фильтр и загружаем драйвер.

2. Инициализируйте детекторы, такие как детектор допустимости соединения и детектор допустимости оператора запроса.

3.Создает объект статистики источника данныхJdbcDataSourceStat。Druid连接池以监控闻名,JdbcDataSourceStat — центр хранения данных!

4. Инициализируйте три массива для хранения соединений с базой данных, удаленных соединений, соединений, которые все еще активны после обнаружения, и инициализируйте соединения с базой данных. Инициализируйте три потока, которые регистрируют потоки, создают соединения с базой данных и определяют, истекает ли время ожидания соединения.

DruidDataSource инициализирует несколько ключевых моментов:

Инициализировать пул соединений

if (createScheduler != null && asyncInit) {
    for (int i = 0; i < initialSize; ++i) {
        submitCreateTask(true);
    }
} else if (!asyncInit) {
    // init connections    
    while (poolingCount < initialSize) {
        try {
            PhysicalConnectionInfo pyConnectInfo = createPhysicalConnection();
            DruidConnectionHolder holder = new DruidConnectionHolder(this, pyConnectInfo);
            connections[poolingCount++] = holder;
        } catch (SQLException ex) {
            LOG.error("init datasource error, url: " + this.getUrl(), ex);
            if (initExceptionThrow) {
                connectError = ex;
                break;
            } else {
                Thread.sleep(3000);
            }
        }
    }
    if (poolingCount > 0) {
        poolingPeak = poolingCount;
        poolingPeakTime = System.currentTimeMillis();
    }
}

Когда свойство настроеноcreateScheduler (пул потоков),asyncInit(логическое) иЗначение asyncInit равно true, выполняется асинхронная инициализация, в противном случае основной поток блокируется до завершения инициализации.poolingCount — текущий размер пула линий.

private void submitCreateTask(boolean initTask) {
    createTaskCount++;
    //创建生成连接的Runnable任务
    CreateConnectionTask task = new CreateConnectionTask(initTask);
    if (createTasks == null) {
        //long类型数组用于存放Runnable任务
        createTasks = new long[8];
    }
    boolean putted = false;
    for (int i = 0; i < createTasks.length; ++i) {
        if (createTasks[i] == 0) {
            createTasks[i] = task.taskId;
            putted = true;
            break;
        }
    }
    if (!putted) {
        //当createTasks数组满时,扩容为之前数组大小的1.5倍。
        long[] array = new long[createTasks.length * 3 / 2];
        System.arraycopy(createTasks, 0, array, 0, createTasks.length);
        array[createTasks.length] = task.taskId;
        createTasks = array;
    }
    //丢进线程池执行
    this.createSchedulerFuture = createScheduler.submit(task);
}

Метод createPhysicalConnection() возвращает указатель, содержащий ссылку на фактическое соединение.

Объект PhysicalConnectionInfo создает соединение с базой данных в соответствии с настроенным свойством. После того, как соединение создано, инициализируйте соединение (зафиксировать ли автоматически, установить уровень изоляции транзакции, предварительно выполнить
Оператор настройки объема данных в connectionInitSqls), проверка достоверности и выполнение настроенного оператора sql.

Сгенерируйте возвращенные PhysicalConnetionInfo и DruidDataSource
Объект DruidConnectionHolder (объект, с которым фактически работает пул соединений), помещается в массив пула соединений до тех пор, пока размер пула соединений не будет равенначальный размер.

какКогда для asyncInit установлено значение false, соединение создается через цикл while.Основной код выглядит следующим образом.

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

Логика соответствует режиму пула потоков.


На этом пул потоков Druid, обычная настройка параметров и инициализация указанного количества соединений завершены. Осталось еще три создания потока, которые мы оставим в следующей главе для продолжения анализа.


                                                           

                                                         (Сканируйте код, чтобы подписаться на официальный аккаунт)



Примечание. Из-за ограничений уровня документ предназначен только для вашего собственного улучшения, сообщите, если есть несоответствия. (несанкционированная передача запрещена)