
Продолжаем писать сайт на java и сегодня мы поговорим о такой теме как пул соединение или connection pool на английском. Напомню, что это уже четвертая статья, посвященная простому java веб приложению. Остальные можно найти в рубрике Java web.
Коннект к базе данных требует затрат определенного времени. Особенно, если база данных находится удаленно. Если под каждых запрос делать подключение к базе, то отклик нашего приложения будет невероятно низким по скорости. Не говоря уже о ресурсах, которые оно потребит.
Во избежании таких проблем есть пул соединений, который открывает соединение только первый раз, а при закрытии соединения он не закрывает его, а отправляет в пул в случае если кто-то будет делать очередной запрос. По сути, приложение работает через специальный драйвер, который является оберткой для обычного jdbc драйвера и который имеет дополнительный функционал по работе с пулом.
Настройки для пула соединений программист может прописать вручную: количество активных соединений, время ожидания и т.д.
Для особенно активных, можно написать свой connection pool: класс, который буде иметь список соединений. У него будет переопределена функция close, которая будет возвращать соединение обратно в список и много других плюшек вроде таймера открытого соединения. Когда нет конекшина долгое время, соединение закрывается.
Мы не будем изобретать свой велосипед, а воспользуемся готовыми решениями. Так как мы используем Tomcat возьмем его реализацию пула соединений.
Для этого нужно в папке webapp создать папку META-INF и в ней создать xml файл context.xml.
Далее нужно вставить настройки нашего пула в этот файл:
- <?xml version="1.0" encoding="UTF-8"?>
- <Context>
- <!-- Specify a JDBC datasource -->
- <Resource name="jdbc/имяПула" - можно выбрать произвольно
- auth="Container"
- type="javax.sql.DataSource"
- username="Пользователь"
- password="Пароль"
- driverClassName="com.mysql.jdbc.Driver" - если используете mysql
- url="jdbc:mysql://хост:3306/имяБазы?autoReconnect=true"
- validationQuery="select 1"
- maxActive="10"
- maxIdle="4"/>
- </Context>
Здесь указано по минимуму настроек. Полагаю, комментарии излишни.
Теперь осталось только использовать этот код в нашем приложении.
Создадим класс ConnectonPool и сделаем его singletone. Для тех, кто не знает: это когда нельзя создать больше одного экземпляра данного класса.
Для этого делается приватный конструктор и для доступа к экземпляру класса создается специальный метод, который возвращает только один экземпляр класса.
- private ConnectionPool(){
- //private constructor
- }
- private static ConnectionPool instance = null;
- public static ConnectionPool getInstance(){
- if (instance==null)
- instance = new ConnectionPool();
- return instance;
- }
Далее нужно создать метод, через который мы будем получать соединение, но не напрямую, а через пул соединений.
- Context ctx;
- try {
- DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/имяПула");
- c = ds.getConnection();
- e.printStackTrace();
- e.printStackTrace();
- }
- return c;
- }
Тут нужно немного комментариев.
Context — это интерфейс, который представляет собой контекст именования, который состоит из набора привязок имени к объекту. InitialContext — класс, который является исходным контекстом для выполнения операций именования. А говоря простым языком, Context, InitialContext позволяют нам иметь доступ к службам имен и каталогов. Для любопытных советую почитать о Java Naming and Directory Interface (JNDI). Метод lookup() извлекает объект по ссылке. В нашем случае он вынимает объект и кастит его к DataSource. Таким образом мы получили DataSource, который вернет нам Connection.
Полный код:
- import java.sql.Connection;
- import java.sql.SQLException;
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import javax.naming.NamingException;
- import javax.sql.DataSource;
- public class ConnectionPool {
- private ConnectionPool(){
- //private constructor
- }
- private static ConnectionPool instance = null;
- public static ConnectionPool getInstance(){
- if (instance==null)
- instance = new ConnectionPool();
- return instance;
- }
- Context ctx;
- try {
- DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/mydatabase");
- c = ds.getConnection();
- e.printStackTrace();
- e.printStackTrace();
- }
- return c;
- }
- }
Это все о пуле соединений. Как всегда, видео, где я все это приконнектил к проекту и ссылка на гитхаб: https://github.com/caligula95/simplewebapp-part4
Спасибо! Как всегда просто и познавательно))
javax.naming.NameNotFoundException: Name [jdbc/warmstar] is not bound in this Context. Unable to find [jdbc].
Подскажите как эту ошибку исправить?
Вы назвали файл warmstar в папке META-INF, а пытаетесь достать файл jdbc.<Resource name="jdbc/имяПула"
ctx.lookup(«java:comp/env/jdbc/имяПула»);
Отличная статья. Кратко и по делу. Спасибо!
Спасибо за статью. Подскажите при отработке строчки ds = (DataSource) context.lookup(«java:comp/env/jdbc/mydatabase»); значение ds остается null. В дебаге выводит причину:Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial Что это может быть?
Попробуйте добавить строку: System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
«org.apache.naming.java.javaURLContextFactory»); перед строкой ds = (DataSource) context.lookup(«java:comp/env/jdbc/mydatabase»);
Конекшн пул указанный в статье будет работать только в связке с сервером. Если Вы пытаетесь запустить данный функционал в public static void main(String[] args){
} — то есть без сервера, он будет выбрасывать ошибку, которую Вы описали.