В проектах Spring Boot пулы соединений с базами данных стали стандартными. Однако я сталкивался со многими случаями, когда исключения пула соединений приводили к бизнес-ошибкам. У многих опытных инженеров случайно могут возникнуть проблемы в этой области.
В этой статье мы обсудим пул подключений к базе данных и подробно проанализируем механизм его реализации, чтобы лучше понять и избежать потенциальных рисков.
Если пула соединений нет, наш процесс работы с базой данных выглядит следующим образом:
Создание подключения к базе данных является относительно дорогостоящей операцией. Если в сети одновременно находятся сотни или даже тысячи людей, частые операции подключения будут занимать больше системных ресурсов. Однако количество подключений, поддерживаемых базой данных, ограничено, и оно ограничено. возможно создание большого количества подключений. Приведет к зависанию базы данных.
Когда у нас есть пул соединений, при запуске приложения предварительно устанавливаются несколько объектов подключения к базе данных, а затем объекты подключения сохраняются в пуле соединений. Когда приходит запрос клиента, из пула берется объект подключения для обслуживания клиента. Когда запрос завершен, клиент вызывает метод close, помещая объект подключения обратно в пул.
Напротив, преимущества пула соединений очевидны:
1. Повторное использование ресурсов:
Поскольку соединения с базой данных можно использовать повторно, можно избежать больших затрат на производительность, вызванных частым созданием и освобождением соединений, а также повысить стабильность операционной среды системы.
2. Улучшите производительность
Когда делается бизнес-запрос, поскольку соединение с базой данных было создано во время инициализации, его можно использовать немедленно, не дожидаясь установления соединения, что сокращает время ответа.
3. Оптимизируйте распределение ресурсов
Для систем, в которых несколько приложений используют одну и ту же базу данных, вы можете настроить пул подключений к базе данных на уровне приложения, чтобы ограничить максимальное количество доступных подключений к базе данных для определенного приложения, чтобы предотвратить монополизацию определенным приложением всех ресурсов базы данных.
4. Управление подключением
При реализации пула соединений с базой данных занятые соединения могут быть принудительно перезапущены в соответствии с предварительно заданным значением тайм-аута, что позволяет избежать утечки ресурсов, которая может возникнуть при обычных операциях подключения к базе данных.
Следующий код показывает процесс работы базы данных JDBC:
//1. соединятьприезжатьбаза данных
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
//2. Выполнить SQL-запрос
String sqlQuery = "SELECT * FROM mytable WHERE column1 = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sqlQuery);
preparedStatement.setString(1, "somevalue");
resultSet = preparedStatement.executeQuery();
//3. Обработка результатов запроса
while (resultSet.next()) {
int column1Value = resultSet.getInt("column1");
String column2Value = resultSet.getString("column2");
System.out.println("Column1: " + column1Value + ", Column2: " + column2Value);
}
//4. закрыть ресурс
resultSet.close();
preparedStatement.close();
connection.close();
Вышеупомянутый метод часто создает соединения с базой данных и иногда используется на старых страницах JSP. В настоящее время широко используется пул соединений JDBC.
JDBC пул соединений Есть стандартиз Интерфейс источника данныхjavax.sql.DataSource
,Этот класс находится в Java в библиотеке библиотеки.
public interface DataSource extends CommonDataSource, Wrapper {
Connection getConnection() throws SQLException;
Connection getConnection(String username, String password) throws SQLException;
}
Обычно используемые пулы соединений JDBC:
Druid (Пул подключений к базе данных Alibaba) — это библиотека пулов подключений к базе данных с открытым исходным кодом, которая обеспечивает мощные функции управления и мониторинга пула подключений к базе данных.
1. Настройте источник данных Druid.
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/mydatabase");
dataSource.setUsername("yourusername");
dataSource.setPassword("yourpassword");
dataSource.setInitialSize(5); // Начальный пул соединенийразмер
dataSource.setMinIdle(5); // Минимальное количество неактивных соединений
dataSource.setMaxActive(20); // Максимальное количество действий, соединяющихся
dataSource.setValidationQuery("select 1 from dual"); // сердцебиение Query
dataSource.setMaxWait(60000); // максимальное время ожидания
dataSource.setTestOnBorrow(true); // Убедитесь, что соединение действительно
2. Используйте подключение к базе данных.
Connection connection = dataSource.getConnection();
//использоватьсоединятьосуществлятьбаза данныхдействовать
// TODO деловые операции
// Закрыть после использования
connection.close();
3. Закройте источник данных.
dataSource.close();
Реализация нашего источника обучающих данных может быть проанализирована со следующих пяти основных точек зрения:
Сначала мы рассмотрим реализацию источника данных.「Получить соединение」из Скриншот интерфейса,инициализация Можетинициативаипассивныйдва пути。
Master-slave относится к явному вызову метода init, тогда как
вызов
getConnection
методчас,возвращатьсяизобъектдасоединятьинтерфейсиз Класс инкапсуляцииDruidConnectionHolder
。
В рамках метода инициализации источник данных создает три массива пулов соединений.
для этапа инициализации требуется пул соединенийиз「подогреть
」:也就дануждаться按照配置первый创建一定число量изсоединять,и положить его в бассейн,Подать заявку вот таксуществоватьнуждаться Получить соединение, может быть получено непосредственно из пула.
источник данных「подогреть
」разделен насинхронныйиасинхронныйдва пути , см. картинку ниже:
На рисунке выше мы видим, что при синхронном создании соединения собственный JDBC создает соединение и помещает его непосредственно в объект массива соединений. Асинхронное создание потоков требует инициализации createScheduler, но он не настроен по умолчанию.
источник данныхподогретьпосле,Запускаются два потока задач:Создать соединениеиуничтожить соединение。
В этом разделе мы сосредоточимся на изучении Druid источник данных如何Создать соединение。
CreateConnectionThread
Суть в том, что один поток проходит в бесконечном цикле. condition
Ожидание, пробуждённое другими потоками и реализовать логику создания подключения к базе данных.
Автор соответствующим образом упростил метод запуска. При выполнении условий создается соединение с базой данных:
После создания объекта подключения PhysicalConnectionInfo
После этого необходимо сохранить в Connections
массив и пробуждение к другим потокам, чтобы можно было получить соединения из пула.
Мы подробно разобрали процесс создания соединения, и следующим шагом будет процесс получения соединения приложением.
DruidDataSource#getConnection
Метод будет называться DruidDataSource#getConnectionDirect
Способ получения соединения реализуется следующим образом.
Основной процесс – это
1. в for Внутри цикла первый вызов getConnectionDirect
Внутри,вызовgetConnectionInternal
Получить объект подключения из пула;
2. После получения соединения необходимо testOnBorrow
、testWhileIdle
Конфигурация параметров определяет, необходимо ли определять достоверность соединения;
3. Наконец, если вам нужно определить, есть ли утечка соединения, настройте removeAbandoned
Для закрытия соединений, которые были недоступны в течение длительного времени. Эта функция не рекомендуется для использования в производственных средах и используется только для обнаружения и диагностики утечек соединений.
Далее введите Tweet соединениеизфокус:getConnectionInternal
Как получить соединение из пула.
getConnectionInternal()
методсередина拿приезжатьсоединятьиз Есть три способа:
createScheduler
,당пул соединений нет доступных соединений, и текущее количество кредитов изоединять не достигло максимально допустимого количества, и в настоящее время нет других потоков. Создать существование. соединение ;
Суть метода pollLast заключается в следующем: внутри бесконечного цикла ожидание выполняется с помощью метода awaitNanos объекта Condition notEmpty. Если в пуле есть соединение, последнее соединение удаляется и последний элемент массива устанавливается пустым. .
и опрос Последний методразные,первыйметод体Внутри部Нет бесконечного цикла,проходить Condition объект notEmpty из await Метод ждет, пока в пуле появится соединение, удаляет последнее соединение и устанавливает пустой элемент последнего элемента массива.
DruidDataSource
пул В соединениях каждое физическое соединение будет заменено на вложенное. вDruidConnectionHolder
,существование предоставляется потоку приложения до,также будет DruidConnectionHolder
упакованный в DruidPooledConnection
。
Родной из JDBC действовать, 每次осуществлять完деловые операциипосле,Выполнит выключение соединения,дляпул соединений Давайте поговорим,就даобратное соединение, то есть вернуть соединение обратно в пул соединений。
На рисунке ниже показано DruidPooledConnection
из close метод :
существоватьзакрытиеметодсередина,我们фокуссосредоточиться на recycle
Перезагрузочное соединениеметод。
Мы можем понять это просто: поместите соединение в connections Массив из poolingCount позицию и увеличьте ее, затем передайте Condition объект notEmpty Просыпайся, ожидая соединение приложения.
DruidDataSource
соединятьиз销毁 DestroyConnectionThread
Тема завершена :
Каждый раз из запланированной задачи (бесконечный цикл) timeBetweenEvictionRunsMillis
Выполнив один раз, мы фокусируем внимание наdestroyTask
изrun
метод。
destroyTask
изrun
метод 会вызовDruidDataSource#shrink
методустановить согласноиз条件来判断出нуждаться销毁идетский садизсоединять。
Основной процесс:
1. Обход массива пула соединений connections:
Внутренне определите, нужно ли разрушать эти связи или сохранять их живыми. ,并分别加入приезжать对应изв массиве контейнеров。
2. Уничтожить сцену:
idleMillis
>= Разрешенный минимум свободного времени время minEvictableIdleTimeMillis
idleMillis
>= Разрешено максимальное свободное время время maxEvictableIdleTimeMillis
3. Сцена ухода за детьми:
lastFatalErrorTimeMillis
)существоватьсоединять建立час间после4、уничтожить соединение:
Траверсный массив evictConnections Все изоединять и уничтожать один за другим 。
5. Поддерживайте живое соединение:
Траверсный массив keepAliveConnections Все изоединять, проверить соединение , если проверка не пройдена, соединение будет закрыто, в противном случае оно будет заблокировано и повторно добавлено в пул соединений.
В этом разделе мы объясним, как правильно настроить параметр, чтобы обеспечить эффективность базы данныхсоединять.
Многие студенты сталкиваются с проблемой: «После длительного невыполнения операций чтения и записи в базу данных база данных при первом запросе к базе данных сообщит об ошибке, но во второй раз все будет нормально».
那да因为В целях экономии ресурсов база данных будет закрыта, если она долгое время не читалась и не записывалась изоединять。
Автор использует его впервые Druid Я столкнулся с такой проблемой в молодости. Если вам интересно, вы можете прочитать эту статью:
https://www.javayong.cn/codelife/runningforcode.html
На рисунке ниже показано Druid Пример конфигурации источника данных:
Подведем краткий итог Druid из Убедитесь, что соединение действительно Каковы стратегии:
1、уничтожить Поток соединения регулярно обнаруживает все изоединять и закрывает остальные время Слишком большойизсоединять ,Если параметр Keepalive настроен,Тогда его будут продолжать поддерживать, чтобы сохранить изоединять;
2. Приложение каждый раз извлекает данные из источника данных. соединениечас候,будет основано наtestOnBorrow
、testWhileIdle
параметр Обнаружениесоединятьизэффективность。
Поэтому нам нужно сосредоточиться на следующей конфигурации:
A、timeBetweenEvictionRunsMillis – параметр:间隔多久Обнаружение一次空闲соединятьда否有效。
B. Параметр testWhileIdle:Запуск на холостом ходусоединятьиз Обнаружение,Настоятельно рекомендуется установить для этого параметра значение true.
C. Параметр minEvictableIdleTimeMillis:пул соединенийсерединасоединятьмаксимумсвободное время(миллисекунда),соединятьчисло > minIdle && свободное время > minEvictableIdleTimeMillis 。
D. Параметр maxEvictableIdleTimeMillis:пул соединенийсерединасоединятьмаксимумсвободное время,свободное время > maxEvictableIdleTimeMillis, независимо от пула Является ли количество изоединений в соединениях меньшим, чем минимальное количество соединений? 。
E. параметр testOnBorrow:включатьсоединятьиз Обнаружение,Получить Проверьте, действительно ли оно действует при соединении, если установлено значение true , что может гарантировать надежность в наибольшей степени, но производительность станет очень низкой. 。
Автор рекомендует существовать при настройке этих параметров, и DBA и архитекторы должны связаться заранее, каждая компания избаза Стратегии конфигурации данных не совпадают, если база Время выживания конфигурации соединения данных очень короткое, тогда необходимо соответствующим образом уменьшить интервал обнаружения простоя соединения и снизить максимальное и минимальное время работы. время。
В этой статье автор собрал знания по базе данных пулиз соединений.
1、пул соединенийизпреимущество:Повторное использование ресурсов、Улучшите производительность、Оптимизировать распределение ресурсов、соединятьуправлять;
2、JDBC пул соединений:实现Интерфейс источника данныхjavax.sql.DataSource
,Этот класс находится в стандартной библиотеке Java;
3. Пул соединений Druid Принцип реализации:
база данных пула соединений, пул потоков — это пул объектов из идей. объект Пул — это шаблон проектирования,Для управления многоразовыми изобъектами,Уменьшить накладные расходы на создание и уничтожение объектов.
Автор даст вам подробное объяснение в следующей статье:
Справочная статья:
https://segmentfault.com/a/1190000043208041 https://blog.csdn.net/weixin_43790613/article/details/133940617 https://blog.csdn.net/yaomingyang/article/details/123145662