Пул соединений в Java
Пул соединений означает пул объектов соединения. Пул соединений основан на шаблоне проектирования пула объектов. Шаблон проектирования пула объектов используется, когда стоимость (время и ресурсы, такие как ЦП, сеть и ввод-вывод) для создания новых объектов выше. В соответствии с шаблоном проектирования пула объектов приложение заранее создает объект и помещает его в пул или контейнер. Всякий раз, когда нашему приложению требуются такие объекты, оно получает их из пула, а не создает новый.
Приложение, использующее стратегию пула соединений, уже имеет объекты соединения с БД, которые можно использовать повторно. Итак, когда возникает необходимость взаимодействия с базой данных, приложение получает экземпляры подключения из пула. Пул соединений повышает производительность приложений, взаимодействующих с базой данных.
Мы можем создавать собственные реализации пула соединений. Любая структура пула соединений должна выполнять три задачи.
- Создание объектов соединения
- Управлять использованием созданных объектов и проверять их
- Освобождение/уничтожение объектов
С Java у нас есть большой набор библиотек, которые легко доступны. Нам нужно только настроить несколько свойств, чтобы использовать их.
Пул соединений в Java-приложении
Давайте посмотрим на следующие библиотеки:
- Apache Commons DBCP 2
- HikariCP
- C3P0
Давайте посмотрим на приведенные ниже примеры один за другим. Для демонстрационных целей мы будем использовать базу данных MySQL и Eclipse IDE. Мы также создадим простой Java-проект на основе maven с использованием JDK 1.8.
Скрипты базы данных
create database empdb;
use empdb;
create table tblemployee(
empId integer AUTO_INCREMENT primary key,
empName varchar(64),
dob date,
designation varchar(64)
);
insert into tblemployee(empId,empName,dob,designation) values (default,'Adam','1998-08-15','Manager');
insert into tblemployee(empId,empName,dob,designation) values (default,'Smith','2001-01-11','Clerk');
insert into tblemployee(empId,empName,dob,designation) values (default,'James','1996-03-13','Officer');
Пример проекта
Выполните следующие шаги, чтобы создать новый проект.
- Откройте интегрированную среду разработки Eclipse.
- Щелкните меню «Файл» и выберите «Создать» -> «Проект Maven».
- Отобразится показанный ниже экран. Выберите вариант создания простого проекта и нажмите кнопку «Далее».
<старт=\4\>
Нажмите кнопку «Готово».
<старт=\5\>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<старт=\6\>
1) Apache Commons DBCP 2
DBCP принадлежит Apache Common Project. Для DBCP 2.7 требуется Java 8. Чтобы использовать DBCP 2, вам необходимо добавить следующую зависимость в свой проект.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.7.0</version>
</dependency>
Apache DBCP 2.0 предоставляет два типа источника данных (BasicDataSource и PoolingDataSource).
BasicDataSource: как следует из названия, он прост и подходит для наиболее распространенных случаев использования. Он внутренне создает для нас PoolingDataSource.
Давайте рассмотрим следующие шаги для инициализации пула соединений.
- Создайте экземпляр BasicDataSource
- Укажите URL-адрес JDBC, имя пользователя и пароль базы данных
- Укажите минимальное количество незанятых подключений ( Минимальное количество подключений, которые должны оставаться в пуле в любое время)
- Укажите максимальное количество неактивных подключений (Максимальное количество неактивных подключений в пуле)
- Укажите общее максимальное количество подключений.
package com.journaldev.example;
/**
* Java JDBC Connection pool using Apache commons DBCP2 example program
*
* @author pankaj
*/
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.commons.dbcp2.BasicDataSource;
public class DBCP2Demo {
private static BasicDataSource dataSource = null;
static {
dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setMinIdle(5);
dataSource.setMaxIdle(10);
dataSource.setMaxTotal(25);
}
public static void main(String[] args) throws SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery("select * from tblemployee");
while (resultSet.next()) {
System.out.println("empId:" + resultSet.getInt("empId"));
System.out.println("empName:" + resultSet.getString("empName"));
System.out.println("dob:" + resultSet.getDate("dob"));
System.out.println("designation:" + resultSet.getString("designation"));
}
} finally {
resultSet.close();
statement.close();
connection.close();
}
}
}
Выход:
empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer
PoolingDataSource: обеспечивает большую гибкость. Вам нужно только изменить код, который создает DataSource. Остальной код останется прежним.
Давайте рассмотрим следующие шаги для инициализации пула соединений:
- Создайте экземпляр ConnectionFactory, используя URL-адрес JDBC.
- Создайте экземпляр PoolableConnectionFactory, используя экземпляр ConnectionFactory, созданный на шаге 1.
- Создайте экземпляр GenericObjectPoolConfig и задайте свойства максимального простоя, минимального простоя и максимального подключения.
- Теперь инициализируйте ObjectPool, используя экземпляры, созданные на шагах 2 и 3.
- Теперь установите пул как экземпляр PoolableConnectionFactory
- Наконец, инициализируйте экземпляр DataSource
private static DataSource dataSource = null;
static {
Properties properties = new Properties();
properties.setProperty("user", "root");
properties.setProperty("password", "root");
ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:mysql://localhost:3306/empdb",
properties);
PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null);
GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(25);
config.setMaxIdle(10);
config.setMinIdle(5);
ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory, config);
poolableConnectionFactory.setPool(connectionPool);
dataSource = new PoolingDataSource<>(connectionPool);
}
2) ХикариКП
HikariCP быстрый, надежный и простой. Это одно из предпочтительных решений для пула соединений. Фреймворки, такие как Spring Boot 2.x, используют его в качестве диспетчера соединений по умолчанию.
Чтобы использовать HikariCP, добавьте следующую зависимость в pom.xml нашего проекта.
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.5</version>
</dependency>
Конфигурация HikariCP:
Мы можем использовать конфигурацию на основе Java, как показано в нашей программе ниже, или мы можем использовать файл свойств для настройки HikariCP. Давайте посмотрим на свойства ниже.
- idleTimeout: время в миллисекундах, в течение которого объект соединения может оставаться в пуле бездействующим. Он работает со свойствами MinimumIdle и MaximumPoolSize. Через указанное время объект подключения будет освобожден.
- connectionTimeout: время в миллисекундах, в течение которого клиент будет ожидать подключения объекта из пула. Если лимит времени достигнут, будет выдано исключение SQL.
- autoCommit: мы можем указать значение true или false, и если для него установлено значение true, оно будет автоматически фиксировать все выполняемые операторы SQL, а если установлено значение false, нам нужно будет фиксировать операторы SQL вручную
- cachePrepStmts: включить кэширование для оператора Prepare
- minimumIdle: минимальное количество объектов соединения, которое должно оставаться в пуле в любое время.
- maximumPoolSize: максимальное количество подключений, которые могут оставаться в пуле.
package com.journaldev.example;
/**
* Java JDBC Connection pool using HikariCP example program
*
* @author pankaj
*/
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class HikariCPDemo {
private static HikariDataSource dataSource = null;
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/empdb");
config.setUsername("root");
config.setPassword("root");
config.addDataSourceProperty("minimumIdle", "5");
config.addDataSourceProperty("maximumPoolSize", "25");
dataSource = new HikariDataSource(config);
}
public static void main(String[] args) throws SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery("select * from tblemployee");
while (resultSet.next()) {
System.out.println("empId:" + resultSet.getInt("empId"));
System.out.println("empName:" + resultSet.getString("empName"));
System.out.println("dob:" + resultSet.getDate("dob"));
System.out.println("designation:" + resultSet.getString("designation"));
}
} finally {
resultSet.close();
statement.close();
connection.close();
}
}
}
Выход:
empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer
3) С3Р0
C3P0 — одна из старейших библиотек. Как правило, он используется с Hibernate. Чтобы использовать C3P0, нам нужно добавить следующую зависимость в проект.
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
Мы можем настроить следующие свойства с помощью C3P0.
- driverClass: предпочтительный драйвер Jdbc
- jdbcUrl: URL-адрес JDBC для базы данных.
- initialPoolSize: количество подключений, созданных в пуле при запуске.
- acquireIncrement: необходимо создать количество новых подключений, если текущего размера недостаточно.
- maxIdleTime: количество секунд, в течение которых соединение может оставаться в пуле без использования.
- maxPoolSize: максимальное количество подключений, которые могут оставаться в пуле.
- minPoolSize: минимальное количество объектов соединения, которое должно оставаться в пуле в любое время.
package com.journaldev.example;
/**
* Java JDBC Connection pool using C3PO example program
*
* @author pankaj
*/
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Demo {
static ComboPooledDataSource comboPooledDataSource = null;
static {
comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/empdb?useSSL=false");
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("root");
comboPooledDataSource.setMinPoolSize(3);
comboPooledDataSource.setAcquireIncrement(3);
comboPooledDataSource.setMaxPoolSize(30);
}
public static void main(String[] args) throws SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = comboPooledDataSource.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery("select * from tblemployee");
while (resultSet.next()) {
System.out.println("empId:" + resultSet.getInt("empId"));
System.out.println("empName:" + resultSet.getString("empName"));
System.out.println("dob:" + resultSet.getDate("dob"));
System.out.println("designation:" + resultSet.getString("designation"));
}
} finally {
resultSet.close();
statement.close();
connection.close();
}
}
}
Выход:
Aug 29, 2020 8:59:05 PM com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
INFO: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge9kqacgbp7hjpftse6|77a567e1, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> null, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge9kqacgbp7hjpftse6|77a567e1, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/empdb?useSSL=false, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 30, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
empId:1
empName:Adam
dob:1998-08-15
designation:Manager
empId:2
empName:Smith
dob:2001-01-11
designation:Clerk
empId:3
empName:James
dob:1996-03-13
designation:Officer
Это все, что касается примера примера пула соединений JDBC, я надеюсь, что ничего важного здесь не пропущено.
Ссылки: C3P0