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() возвращает указатель, содержащий ссылку на фактическое соединение.
какКогда для 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, обычная настройка параметров и инициализация указанного количества соединений завершены. Осталось еще три создания потока, которые мы оставим в следующей главе для продолжения анализа.
(Сканируйте код, чтобы подписаться на официальный аккаунт)
Примечание. Из-за ограничений уровня документ предназначен только для вашего собственного улучшения, сообщите, если есть несоответствия. (несанкционированная передача запрещена)