Поиск по сайту:

Пул соединений в 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');

Пример проекта

Выполните следующие шаги, чтобы создать новый проект.

  1. Откройте интегрированную среду разработки Eclipse.
  2. Щелкните меню «Файл» и выберите «Создать» -> «Проект Maven».
  3. Отобразится показанный ниже экран. Выберите вариант создания простого проекта и нажмите кнопку «Далее».

<старт=\4\>

  • Введите любой идентификатор группы, идентификатор артефакта, имя и описание.
  • Нажмите кнопку «Готово».

    <старт=\5\>

  • Добавьте следующую зависимость в pom.xml для MySQL.
  • <dependency>
    	<groupId>mysql</groupId>
    	<artifactId>mysql-connector-java</artifactId>
    	<version>5.1.49</version>
    </dependency>
    

    <старт=\6\>

  • Щелкните правой кнопкой мыши проект, выберите Maven -> Обновить проект -> ОК. Он загрузит все зависимости.
  • 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.

    Давайте рассмотрим следующие шаги для инициализации пула соединений.

    1. Создайте экземпляр BasicDataSource
    2. Укажите URL-адрес JDBC, имя пользователя и пароль базы данных
    3. Укажите минимальное количество незанятых подключений ( Минимальное количество подключений, которые должны оставаться в пуле в любое время)
    4. Укажите максимальное количество неактивных подключений (Максимальное количество неактивных подключений в пуле)
    5. Укажите общее максимальное количество подключений.

    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. Остальной код останется прежним.

    Давайте рассмотрим следующие шаги для инициализации пула соединений:

    1. Создайте экземпляр ConnectionFactory, используя URL-адрес JDBC.
    2. Создайте экземпляр PoolableConnectionFactory, используя экземпляр ConnectionFactory, созданный на шаге 1.
    3. Создайте экземпляр GenericObjectPoolConfig и задайте свойства максимального простоя, минимального простоя и максимального подключения.
    4. Теперь инициализируйте ObjectPool, используя экземпляры, созданные на шагах 2 и 3.
    5. Теперь установите пул как экземпляр PoolableConnectionFactory
    6. Наконец, инициализируйте экземпляр 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