2012-04-20 2 views
1

У меня есть главный сервлет контроллера, в котором я создаю источник . Сервлет открывает и закрывает соединения. В основном, сервлет создает команду из приложения, используя «фабричный шаблон». здесь некоторый код, чтобы объяснить:«Ленивая инициализация» соединений jdbc из jdi datasource/pool pool: осуществимость

public void init() throws ServletException { 
    super.init(); 
    try { 
      datasource =(DataSource) getServletContext().getAttribute("DBCPool"); 
    } 
    catch (Exception e) { 

    } 
} 
protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException { 
    //some code... 
    Connection connection = null; 
    if(cmd.mightNeedLazyLoadingAConnection) 
    { 

     connection = null; 
    } 
    else 
     connection = getConnection();//where getConnection is a method: datasource.getconnection(); 

     //now a command (a java class) is instantied, to which the "null" CONNECTION obj is passed as parameter 
    cmdFactory.getInstance().getCommand(Cmd).execute(tsk,connection); 


    //some code 

//Then wherever there is catch exception i close() the connection 
// and it is always closed in finally 
finally { 
if(connection!=null) 
    connection.close() 
} 

} 

Теперь это имеет проблему для первого случая, то есть связи = нуль, так как он не имеет и не закрывает соединение в «наконец» части (объяснил, почему в Обновление ниже). «Соединение = нуль»

для случаев, когда команды не может понадобиться, чтобы открыть соединение с базой данных, поскольку данные он ищет кэшируются в identity map.

Я пытался передать "Соединение" OBJ в качестве "нулевого" параметра в .Execute (TSK, соединение);, а затем в соответствующем классе Java, чтобы открыть соединение если необходимо

-> он сделал открыть соединение внутри команды, однако, когда процесс переходит обратно к сервлету: «Соединение» является недействительным, поскольку при этом не закрыто.
Что я могу сделать, чтобы сделать «Подключение» Значение obj обновляется, поэтому, когда он снова находится в сервлете, он больше не «Null», и я мог бы его закрыть?

Я вообще предпочитаю использовать сервлет контроллера, который открывает/закрыть соединения дБ, так что было бы лучшим способом справиться такого рода сценарий, в котором вы должны сделать какой-то «отложенной загрузки» а соединение с базой данных из бассейна и в то же время сохранить открытие/закрытие соединения db, назначенного сервлету?

Update (объяснить далее):

  • говорят, у меня есть команда: X.java
  • эта команда может/не может требуется подключение дБ (зависит, если данные поиск которых находится на идентификационной карте или нет)

Система, которую я хотел бы иметь:

(1) "запрос клиента"

(2) --->"Servlet": command.execute (соединение) // где соединение = нуль на текущий

(3) --->«Команда X»: Нужно ли мне переходить в базу данных или запись находится в карте идентификации?
(3.а) Случай, когда это необходимо, чтобы перейти к базе данных:
подключения (3.А.1) = datasource.getconnection
(3.a.2) идут получить данные

(4) - ->назад в сервлет: близко «соединение» в «Servlet»

Прямо сейчас он не работает до тех пор (3.a.2), но когда-то еще в (4), то оказывается, что соединение по-прежнему " null "и, следовательно, код:

finally { 
if(connection!=null) 
    connection.close() 
} 

не работает (не закрывает соединение) и, таким образом, пул db так истощается. Каким образом соединение - которое начинается как «null» и изменяется внутри команды «X» - обновляется «globaly» до его нового значения, а не только «обновляется» внутри области действия команды «X»?

РАСТВОР (S)

В случае, если вы сталкиваетесь с таким же сценарием, вы можете выбрать из этих -решений:

  • Вы можете использовать LazyConnectionDataSourceProxy как упоминался на @Ryan Stewart за «чистую абстракцию» и более профессиональное решение

  • Или, если вы хотите использовать мое решение, описанное ниже (в основном я реализовал класс, похожий на «LazyConnectionDataSourceProxy», но это не так чиста, она имеет меньше абстракции деталей, чем «LazyConnectionDataSourceProxy»)

Мой личный решение, Детали:

  • Я создал класс «Helper», который конструктор принимает «источник данных» в качестве параметра
  • Этот вспомогательный класс имеет методы: «Ленивый получить» соединение с бассейном, "Клоса e "connection
  • Этот класс создается при помощи сервлета, и он получает соединение с бассейном Только при необходимости в приложении.

Это код, я добавил/модифицирована в сервлет:

Connection connection = null; 
if(cmd.mightNeedLazyLoadingAConnection) 
{ 

    helper hp = new helper(datasource); 
    cmdFactory.getInstance().getCommand(Cmd).execute(tsk,hp); 
} 
else 
{ 
    connection = getConnection(); 
    cmdFactory.getInstance().getCommand(Cmd).execute(tsk,connection); 
} 

Тогда говорят в команде "X", требуется подключение дб я сделать:

Connection connection = hp.LazyGet();//Now got a connection from the pool 

И таким образом, когда поток процесса возвращается к уровню сервлета, я могу:

  • Закрыть
  • Откат
  • commit
  • и т.д ..

Все на этом объекте hp вспомогательного класса.

Какие преимущества я получаю от этого:

  • ограничиваю всех баз данных открытия/закрытия/фиксации/отката в один место, то есть сервлет, который является ответственным за выполнением команд ,
  • Имея случаев: никогда не нуждается в дб/всегда нуждается в дБ/может понадобиться дб теперь, таким образом я уменьшил звонки в базу данных 1/3, что довольно много, зная, что вызов базы данных растет экспоненциально с новыми функций и регистрации новых пользователей.

Это не может быть Cleanest обходной путь, но между этим способом и имеющие дополнительные «лишние» звонки 1/3 базы данных, это, безусловно, лучше. Или просто используйте LazyConnectionDataSourceProxy, если вы хотите Протестированный, абстрактный и чистый метод.

ответ

1

Используйте LazyConnectionDataSourceProxy. Затем просто получайте «соединение» каждый раз, но реальное соединение открывается только тогда, когда вы на самом деле делаете то, что его требует. Таким образом, вы подчиняетесь мудрости «create/destroy», которую указал Hiro2k, потому что жизненный цикл соединения полностью управляется вашим сервлетом.

+0

спасибо за советы. Я только что опубликовал свое решение несколько минут назад. Я не использую фреймворки, но я сделал какой-то класс помощника/прокси (проверьте мой ответ). – shadesco

+0

Я ничего не говорил об использовании фреймворка. «LazyConnectionDataSourceProxy» делает почти то же самое, что описывает ваше решение, за исключением того, что он скрывает грязные детали за чистым уровнем абстракции. Нет понятия «может понадобиться соединение» или «ленивый get». Вы просто относитесь к нему как к нормальному 'DataSource', который обеспечивает нормальное' Connection', и вы получаете ленту бесплатно. Это значительно лучший вариант по этим причинам. –

+0

Я вижу .. я перепроверю его и узнаю больше об этом – shadesco

0

В вашем конкретном случае единственный способ сделать это - вернуть соединение. В Java нет пропусков по ссылочной семантике, которые могли бы вам помочь, в отличие от C, где вы могли бы передать ссылку на соединение, а затем установить ее в рамках метода.

Я не рекомендую ваш метод возвращает соединение, вместо того, чтобы помнить это простое правило, и все будет работать, как вы ожидаете:

объект, который создает его, несет ответственность за его уничтожение.

Если вы хотите сделать это, не создавайте соединение для команд, которые не требуют их, а затем добавьте метод в свой командный интерфейс, который просто вернется, если понадобится.

Command command = cmdFactory.getInstance().getCommand(Cmd); 
if(command.requiresConnections){ 
    connection = getConnection(); 
} 
command.execute(tsk,connection); 
+0

thx для советов. Я не могу вернуть соединение, поскольку каждая команда возвращает данные для отправки на клиентскую сторону. Что касается: «Объект, который его создает, несет ответственность за его уничтожение». , очень верно, но это будет означать, что мне нужно будет открыть/закрыть соединение в каждой команде. Я пытаюсь посмотреть, будет ли возможно оставить открытый/закрытый только в одном месте, то есть в сервлете. Если окажется, что нет абсолютно никакого способа, я буду следовать тому, что вы сказали. – shadesco

+0

См. Мое редактирование, я добавил возможное решение для вас. – Hiro2k

+0

еще раз спасибо, но я думаю, вы неправильно поняли мой вопрос, что вы написали, это то, что у меня уже есть в моем коде. Код, поскольку он теперь «Всегда», открывает соединение, и то, что я хочу знать, - это когда команда может/не нуждаться в соединении, как вы передаете нулевой объект «соединение» с командой, а «Там» вы откройте соединение, и когда поток вернется к сервлету, вы «закроете» это «соединение» в сервлете. – shadesco

Смежные вопросы