В сегодняшней статье я расскажу про использование Connection Pool в java для работы с БД (на примере работы с функциями Oracle).
Для работы с БД необходима коннекция. Но когда у нас есть большое приложение и много запросов, то открывать и закрывать коннекции перед каждым запросом довольно трудоемкая задача для системы, на которую уходит порядка нескольких секунд, когда сам запрос может выполняться меньше 1 сек. Если же использовать 1 коннекцию, то в ней могут скапливаться очереди из запросов, замедляя работу системы, т.к. одновременно может выполняться только 1 транзакция. Но есть решение, Connection Pool - механизм, который позволяет управлять множеством соединений.
Рассмотрим работу с ним. Мы используем GlassFish. Поэтому в путь... Заходим в админку GlassFish -> Resources -> JDBC.
Создаем Connection Pool
Name - имя connection pool
Resource Type - это интерфейс, который реализуется конкретными вендорами в драйвере в виде классов. В списке Resource Type доступны следующие типы:
- DataSource - Обычный data source для доступа к коннекциям
- XADataSource - Доступ с использованием механизма распределенных транзакций
- ConnectionPoolDataSource - Доступ с использованием connection pool
Но вендорами, к примеру Oracle, интерфейс DataSource реализуется по умолчанию с использованием Connection Pool (можно прочитать здесь).
DataBase Vendor - поставщик используемого драйвера базы данных

Рис. 1 Создание Connection Pool
На следующем шаге устанавливаем значения необходимых параметров. Достаточно указать всего 3 следующих параметра:
user - имя пользователя для работы с БД
password - пароль
url :
- thin - тип используемого драйвера
- localhost - хост
- 1521 - порт
- XE - название БД (XE стандартное имя для Oracle 10XE)

Рис. 2 Добавление параметров Connection Pool
Затем создаем JDBC ресурс
Называем наш ресурс jdbc/ConncetionPool и выбираем в названии пула имя только что созданного пула.

Рис. 3 Создание JDBC ресурса
Теперь нам необходимо скачать библиотеку ojdbc14.jar с сайта Oracle (мы используем 10 версию) и скопировать ее в domains/domain1/lib нашего сервера. На этом настройки GlassFish закончены и можно перейти к работе с Connection Pool в нашем приложении.
Для этого подключим наш JDBC ресурс в JNDI.
web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/ConnectionPool</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Создадим класс, отвечающий за работу к БД. В него поместим 2 метода (этого нам для начала достаточно) : init(String dataSourceName) - занимающийся инициализацией и getConnection() - отдающий нам коннекцию из Connection pool.
JDBCUtils.java
package com.dataaccess.persistence;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
public class JDBCUtils {
private static final Logger log = Logger.getLogger(JDBCUtils.class.getName());
private DataSource dataSource;
public JDBCUtils() {
}
public void init(String dataSourceName) {
try {
InitialContext initContext = new InitialContext();
dataSource = (DataSource) initContext.lookup(dataSourceName);
} catch (NamingException e) {
log.error("JNDIException: " + e.getMessage());
}
}
public Connection getConnection() throws SQLException {
if (dataSource == null) {
throw new SQLException("DataSource is null.");
}
return dataSource.getConnection();
}
}
Создадим фабрику, через которую мы будем работать с JDBCUtil.
DataAccessFactory.java
package com.dataaccess.persistence;
public class DataAccessFactory {
private static final DataAccessFactory instance = new DataAccessFactory();
private JDBCUtils jdbcUtil;
private DataAccessFactory() {
}
public static DataAccessFactory getInstance() {
return instance;
}
private JDBCUtils prepareJDBCUtils() {
if (jdbcUtil == null) {
jdbcUtil = new JDBCUtils();
jdbcUtil.init("java:comp/env/jdbc/ConnectionPool");
}
return jdbcUtil;
}
public static synchronized JDBCUtils getJDBCUtils() {
return getInstance().prepareJDBCUtils();
}
}
Теперь создадим класс, в котором будем делать сами запросы.
PersistenceManager.java
package com.dataaccess.managers;
import com.dataaccess.persistence.DataAccessFactory;
import com.dataaccess.persistence.JDBCUtils;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import oracle.jdbc.OracleTypes;
public class PersistenceManager {
private static final JDBCUtils jdbcUtils = DataAccessFactory.getJDBCUtils();
public static Map<Integer, String> getData(String param1, String param2, String param3) throws Exception {
Map<Integer, String> data = new HashMap<Integer, String>();
Connection con = null;
CallableStatement st = null;
ResultSet result = null;
try {
con = jdbcUtils.getConnection();
st = con.prepareCall("{ ? = call get_data(?, ?, ?)}");
st.registerOutParameter(1, OracleTypes.CURSOR);
st.setString(2, param1);
st.setString(3, param2);
st.setString(4, param3);
st.execute();
result = (ResultSet) st.getObject(1);
while (result.next()) {
data.put(result.getInt(1), result.getString(2));
}
} finally {
if (result != null) {
result.close();
}
if (st != null) {
st.close();
}
if (con != null) {
con.close();
}
}
return data;
}
}
Здесь я распишу подробнее:
// так происходит вызов функции Oracle, которая возвращает нам cursor
st = con.prepareCall("{ ? = call get_data(?, ?, ?)}");
// регистрируем тип данных возвращаемого значения
st.registerOutParameter(1, OracleTypes.CURSOR);
// устанавливаем входные параметры в функцию.
st.setString(2, param1);
st.setString(3, param2);
st.setString(4, param3);
Все довольно просто. Пишите. Отвечу.