angle-left

JDBC Connection Pool (GlassFish + Oracle)

В сегодняшней статье я расскажу про использование 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);

 

Все довольно просто.  Пишите. Отвечу.

S/N/V/      

tuneit
 

Образование:  СПБГУ ИТМО. Кафедра вычислительной техники.

Интересы: железо, софт, web-приложения (java EE, ICEfaces, LIferay, DotCMS, PHP, CSS, html, JavaScript, CMS Drupal, PostgreSQL, MySql, Oracle...)

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

Контакты:

  •   Nicola.russian
  •   Nicola.russian