Connection pool java примеры

Простейший Connection pool без DataSource в Java

Ни для кого не секрет, что в Java EE Connection Pool реализуется используя Data Source. С примером реализации в Apache Tomcat можно ознакомиться по этой ссылке: habrahabr.ru/post/101342. Но что делать, если мы используем только Java SE и нам нужно организовать многопоточный доступ к базе данных по схеме Connection Pool. Ведь сервера приложений у нас в данном случае нет, следовательно, использовать Data Source мы не можем, а для создания соединений к бд нам придется скорее всего использовать java.sql.DriverManager. Можно еще использовать в замену данному подходу что-нибудь из этой статьи: docs.oracle.com/javase/jndi/tutorial/ldap/connect/pool.html. Скорее всего кем-то данный подход уже реализовывался на Java, по крайней мере я не обнаружил такую реализацию в сети. И я решил изобрести свой велосипед. Было бы хорошо, если в поисковике при поиске Connection pool в Java выходила ссылка на эту статью, дополненную и отредактированную по комментариям и дополнениям от habr.ru, и эта статья была бы полезна кому-нибудь. Если стало интересно, то прошу под кат.

Реализуем все в виде класса, конструктор которого принимает на вход начальное количество соединений в пуле и параметры подключения к бд (название загружаемого класса из драйвера и строка подключения вместе с именем пользователя и паролем). Назовем класс ConnectionPool, его конструктор будет иметь вид:

public ConnectionPool(String url, String driver, int initConnCnt) < try < Class.forName(driver); >catch (Exception e) < e.printStackTrace(); >this.url = url; for (int i = 0; i < initConnCnt; i++) < availableConns.addElement(getConnection()); >> 

url — это строка подключения, для MS SQL Server она будет иметь вид наподобие: jdbc:sqlserver://192.168.0.1;databaseName=dbname;username=username;password=pwd. Можно разделить имя пользователя и пароль, передавать их отдельно в DriverManager. Здесь все в одном месте, по крайней мере мне так показалось удобней. Один из допустимых драйверов для работы с MS SQL Server имеет следующий вид: com.microsoft.sqlserver.jdbc.SQLServerDriver.
В данном классе должны объявляться два вектора:

private Vector availableConns = new Vector(); private Vector usedConns = new Vector(); 

Первый будет содержать список доступных для использования соединений, второй список используемых в любой момент времени.
Кроме этого определяется переменная url, которая будет хранить строку подключения к бд:

Читайте также:  Бот для напоминаний telegram python

В конструкторе используется функция getConnection, которая просто создает новое подключение. Его реализация следующая:

private Connection getConnection() < Connection conn = null; try < conn = DriverManager.getConnection(url); >catch (Exception e) < e.printStackTrace(); >return conn; > 

Итак, мы имеем вектор availableConns, заполненный Connection’ами в количестве initConnCnt штук, ни один из которых пока не используется непосредственно по назначению, т.е. для доступа к бд. Теперь напишем функцию retrieve, эта функция забирает из availableConns очередной Connection и добавляет его в usedConns, затем возвращает это соединение, тем самым он становится используемым:

public synchronized Connection retrieve() throws SQLException < Connection newConn = null; if (availableConns.size() == 0) < newConn = getConnection(); >else < newConn = (Connection) availableConns.lastElement(); availableConns.removeElement(newConn); >usedConns.addElement(newConn); return newConn; > 

Логика понятна: сначала мы проверяем, есть ли свободные соединения, если нет, то мы создаем новое подключение, если есть, то мы извлекаем последний элемент из availableConns и удаляем его из вектора свободных соединений. Затем мы только что созданное соединение или извлеченное из списка свободных добавляем в список используемых строкой

usedConns.addElement(newConn); 

и возвращаем это соединение. Конечно же без synchronized не обойтись. Как же иначе? Доступ то многопоточный, вдруг двум потокам выделится одно и то же соединение! Когда соединение становится не нужным, то мы выполняем обратную операцию, иначе говоря putback:

public synchronized void putback(Connection c) throws NullPointerException < if (c != null) < if (usedConns.removeElement(c)) < availableConns.addElement(c); >else < throw new NullPointerException("Connection not in the usedConns"); >> > 

Логика тоже понятна и не требует объянений.
Дальше можно по необходимости написать кучу всяких дополнительных функций, которые предоставляют доступ к дополнительной информации, например, функция для получения количества свободных соединений будет выглядеть следующим образом:

public int getAvailableConnsCnt()
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Vector; class ConnectionPool < private VectoravailableConns = new Vector(); private Vector usedConns = new Vector(); private String url; public ConnectionPool(String url, String driver, int initConnCnt) < try < Class.forName(driver); >catch (Exception e) < e.printStackTrace(); >this.url = url; for (int i = 0; i < initConnCnt; i++) < availableConns.addElement(getConnection()); >> private Connection getConnection() < Connection conn = null; try < conn = DriverManager.getConnection(url); >catch (Exception e) < e.printStackTrace(); >return conn; > public synchronized Connection retrieve() throws SQLException < Connection newConn = null; if (availableConns.size() == 0) < newConn = getConnection(); >else < newConn = (Connection) availableConns.lastElement(); availableConns.removeElement(newConn); >usedConns.addElement(newConn); return newConn; > public synchronized void putback(Connection c) throws NullPointerException < if (c != null) < if (usedConns.removeElement(c)) < availableConns.addElement(c); >else < throw new NullPointerException("Connection not in the usedConns array"); >> > public int getAvailableConnsCnt() < return availableConns.size(); >> 

Источник

Database Connection Pool

Добрый день, хабралюди!
2 недели назад я начал работать juior java разработчиком, и, соответственно, получать много нового для себя опыта. Сегодня я решил совместить приятное с полезным и начать этот опыт оформлять в письменные мысли — в виде статей о тех технологиях, принципах и приёмах, с которыми я столкнулся на своём джуниорском пути. Нижеследующая статья — первая среди подобных, и выкладывая её здесь, я хочу, во-первых, понять, нужны ли хабрасообществу подобные вещи — рассказы не умудрённых опытом и сотнями проектов старожилов, а небольшие попытки поделится опытом от джуниора джуниору, — а во-вторых, как обычно, услышать замечания, исправления и критику.
Спасибо за внимание.

Подавляющее большинство современных веб-приложений использует базы данных для хранения информации. Приложение может обмениваться информацией с БД, используя соединение (database connection). Если создавать при каждом обращении к БД, получается проигрыш во времени: выполнение транзакции может занять несколько милисекунд, в то время как на создание соединения может уйти до нескольких секунд. С другой стороны, можно создать одно-единственное соединение (например, используя шаблон «Singleton») и обращаться к базе данных только через него. Но это решение чревато проблемами, в случае высокой нагрузки: если одновременно сто пользователей попытается получить доступ к базе данных используя одно соединение, образуется очередь, что также пагубно сказывается на производительности приложения.

Database Connection Pool (dbcp) — это способ решения изложенной выше проблемы. Он подразумевает, что в нашем распоряжении имеется некоторый набор («пул») соединений к базе данных. Когда новый пользователь запрашивает доступ к БД, ему выдаётся уже открытое соединение из этого пула. Если все открытые соединения уже заняты, создаётся новое. Как только пользователь освобождает одно из уже существующих соединений, оно становится доступно для других пользователей. Если соединение долго не используется, оно закрывается.

Пример реализации простейшего пула соединений можно найти на официальном сайте java.sun.com: Connection Pooling

Поскольку подобный подход наиболее полезен в случае enterprise- и web-приложений, вполне логично, что такой популярный контейнер сервлетов, как Apache Tomcat предоставляет собственное решение для создания dbcp. Решение это основанно на библиотеке apache-commons-dbcp. Чтобы реализовать поддержку пула соединений с своём приложении, нужно пройти через несколько этапов.

Во-первых, нужно объявить новый ресурс в контексте приложения. Ресурс (в нашем случае — БД) описывается следующим кодом:

type=»javax.sql.DataSource» maxActive=»100″
maxIdle=»30″ maxWait=»10000″
username=»username»
password=»password»
driverClassName=»jdbc.driver.name»
url=»jdbc:protocol://hostname:port/dbname»/>

Контекст приложения описывается XML-файлом. Я считаю правильным хранить его в %document_root%/META-INF/context.xml, однако это не единственный вариант. Подробней про контекст можно почитать на сайте Tomcat’a: The Context Container.

Теперь нужно добавить ссылку на этот ресурс в web.xml:

Теперь мы можем использовать этот ресурс в нашем приложении. Для того чтобы получить объект Connection для выполнения sql-кода, исопльзуется следующий код:

InitialContext initContext= new InitialContext();
DataSource ds = (DataSource) initContext.lookup(«java:comp/env/jdbc/dbconnect»);
Connection conn = ds.getConnection();

Для получения источника данных (data source) используется механизм JNDI (подробнее про него можно почитать здесь)

Всё! Теперь вы можете выполнить conn.createStatement() и реализовать логику работы с БД. В конце, как обычно, следует закрыть соединение (conn.close()), однако в отличии от обычного соединения через драйвер JDBC, это соединение на самом деле не закроется: оно будет помечено в пуле как свободное, и его можно будет переиспользовать позже. Перед возвратом соединения в пул все Statement’ы и ResultSet’ы, полученные с помощью этого соединения, автоматически закрываются в соответствии с API (спасибо Colwin за замечание).

Источник

Примеры Java для демонстрации пулов подключений

Область применения: база данных Azure для MySQL — отдельный сервер

База данных Azure для MySQL — один сервер находится на пути прекращения поддержки. Настоятельно рекомендуется выполнить обновление до База данных Azure для MySQL — гибкий сервер. Дополнительные сведения о переходе на База данных Azure для MySQL —гибкий сервер см. в статье Что происходит с База данных Azure для MySQL отдельным сервером?

Приведенный ниже пример кода иллюстрирует использование пулов подключений в Java.

import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashSet; import java.util.Set; import java.util.Stack; public class MySQLConnectionPool < private String databaseUrl; private String userName; private String password; private int maxPoolSize = 10; private int connNum = 0; private static final String SQL_VERIFYCONN = "select 1"; StackfreePool = new Stack<>(); Set occupiedPool = new HashSet<>(); /** * Constructor * * @param databaseUrl * The connection url * @param userName * user name * @param password * password * @param maxSize * max size of the connection pool */ public MySQLConnectionPool(String databaseUrl, String userName, String password, int maxSize) < this.databaseUrl = databaseUrl; this.userName = userName; this.password = password; this.maxPoolSize = maxSize; >/** * Get an available connection * * @return An available connection * @throws SQLException * Fail to get an available connection */ public synchronized Connection getConnection() throws SQLException < Connection conn = null; if (isFull()) < throw new SQLException("The connection pool is full."); >conn = getConnectionFromPool(); // If there is no free connection, create a new one. if (conn == null) < conn = createNewConnectionForPool(); >// For Azure Database for MySQL, if there is no action on one connection for some // time, the connection is lost. By this, make sure the connection is // active. Otherwise reconnect it. conn = makeAvailable(conn); return conn; > /** * Return a connection to the pool * * @param conn * The connection * @throws SQLException * When the connection is returned already or it isn't gotten * from the pool. */ public synchronized void returnConnection(Connection conn) throws SQLException < if (conn == null) < throw new NullPointerException(); >if (!occupiedPool.remove(conn)) < throw new SQLException( "The connection is returned already or it isn't for this pool"); >freePool.push(conn); > /** * Verify if the connection is full. * * @return if the connection is full */ private synchronized boolean isFull() < return ((freePool.size() == 0) && (connNum >= maxPoolSize)); > /** * Create a connection for the pool * * @return the new created connection * @throws SQLException * When fail to create a new connection. */ private Connection createNewConnectionForPool() throws SQLException < Connection conn = createNewConnection(); connNum++; occupiedPool.add(conn); return conn; >/** * Crate a new connection * * @return the new created connection * @throws SQLException * When fail to create a new connection. */ private Connection createNewConnection() throws SQLException < Connection conn = null; conn = DriverManager.getConnection(databaseUrl, userName, password); return conn; >/** * Get a connection from the pool. If there is no free connection, return * null * * @return the connection. */ private Connection getConnectionFromPool() < Connection conn = null; if (freePool.size() >0) < conn = freePool.pop(); occupiedPool.add(conn); >return conn; > /** * Make sure the connection is available now. Otherwise, reconnect it. * * @param conn * The connection for verification. * @return the available connection. * @throws SQLException * Fail to get an available connection */ private Connection makeAvailable(Connection conn) throws SQLException < if (isConnectionAvailable(conn)) < return conn; >// If the connection is't available, reconnect it. occupiedPool.remove(conn); connNum--; conn.close(); conn = createNewConnection(); occupiedPool.add(conn); connNum++; return conn; > /** * By running a sql to verify if the connection is available * * @param conn * The connection for verification * @return if the connection is available for now. */ private boolean isConnectionAvailable(Connection conn) < try (Statement st = conn.createStatement()) < st.executeQuery(SQL_VERIFYCONN); return true; >catch (SQLException e) < return false; >> // Just an Example public static void main(String[] args) throws SQLException < Connection conn = null; MySQLConnectionPool pool = new MySQLConnectionPool( "jdbc:mysql://mysqlaasdevintic-sha.cloudapp.net:3306/", "", "", 2); try < conn = pool.getConnection(); try (Statement statement = conn.createStatement()) < ResultSet res = statement.executeQuery("show tables"); System.out.println("There are below tables:"); while (res.next()) < String tblName = res.getString(1); System.out.println(tblName); >> > finally < if (conn != null) < pool.returnConnection(conn); >> > > 

Источник

Оцените статью