Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> JDBC как? 
:(
    Опции темы
Се ля ви
Дата 4.5.2005, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 8
Всего: 127



Гость_junior

Так, погоди, ты какой вариант используешь?

Я чего-то не пойму - у тебя ошибка на уровне компиляции кода или на уровне выполнения? В том варианте, который дал я проблемы "КлассНотФоунд" не должно быть.

Кароче, компилятор у тебя драйвер оракла не видит, или JRE?

Что бы увидел компилятор, надо его в библиотеку грузить - просто так jre/lib.ext не поможет. Она годится на уровне выполнения, если будешь подгружать драйвер выражением
Код
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();

Добавлено @ 11:03
если же ты import`ируешь класс явно - то он должен быть в составе библиотеки твоего проекта...


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
Гость_junior
Дата 4.5.2005, 20:20 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Цитата
Я чего-то не пойму - у тебя ошибка на уровне компиляции кода или на уровне выполнения?

Да, ошибка на стадии компиляции.

Цитата
Просто многие IDE, похоже, подменяют classpath на свое значение. Не знаю, как с этим у NetBeans.

Как узнать значение подмененной переменной?

Спасибо
  Вверх
Се ля ви
Дата 4.5.2005, 22:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 8
Всего: 127



Гость_junior, NetBeans у тебя какой версии?


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
Stampede
Дата 5.5.2005, 00:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 24
Всего: 144



Цитата(Stampede @ 3.5.2005, 22:24)
Для этого служит метод finalize(), но использовать его для управления жизненным циклом таких нежных ресурсов как датабазные коннекции - идея не очень хорошая. Почему - могу объяснить. Потом.


Цитата(Lamer @ 4.5.2005, 09:32)
Объясни сейчас, плз


Объясняю smile

Вот у Се ля ви приведенный им в качестве примера класс реализует некий метод доступа к датабазным данным. Причем у него вообще наличествует только один такой метод и соответственно одна переменная типа Statement. Он даже по этой причине не хранит ссылку на Connection, полагая, что ее всегда можно вытащить через стейтмент. Это очень близорукое решение, потому что вдруг мы захотим добавить еще один метод доступа с другим SQL запросом? Тогда придется постоянно пересоздавать Connection.createStatement("select blah-bla-blah"). Так и будем все время выдергивать соединение из стейтмента?

Кроме того, при таком подходе (один класс - один метод доступа) число таких классов даже в среднем по сложности приложении может быть весьма значительным. Между тем каждый из этих классов содержит зашитые внутри параметры соедиения! То есть чтобы переключиться, скажем, с тестовой конфигурации на рабочую, мы должны внести изменения в n-ное количество классов?

Но допустим это был просто пример, чтобы продемонстрировать процесс установления соединения. Допустим. в реальном приложении все-таки есть выделенный менеджер соединений, который конфигурируется из какого-нибудь файла конфигурации и так или иначе выдает по нашему требованию новое соединение.

Все равно получается ерунда. Если каждый такой класс требует в единоличное пользование отдельное соединение, то это чревато следующими ситуациями:

- На этапе прототипирования функциональность у нас небогатая, и число таких классов (для определенности предлагаю называть их DAC - data access classes) невелико. Ну, скажем, десять. Соответственно, имеем десять отрытых соединений. Ничего, конечно, хорошего, но да ладно. Но вот проект развивается, функциональность разрастается и в какой-то момент мы обнаруживаем, что у нас уже 50 соедиений. И при попытке добавить еще один класс СУБД говорит: извините, товарисч, вы исчерпали лимит соединений. Хотите больше - докупайте дополнительную лицензию.

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

- Но это еще даже не самое страшное. Гораздо хуже то, что доступ к данным при таком подходе у нас осуществляется из разных соединений, а соответственно - в раздельных транзакциях! И когда у нас начнут ни с того ни с сего выскакивать сообщения о взаимных блокировках - я тебя уверяю, мало никому не покажется.

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

Теперь у нас уже больше контроля над тем. что мы делаем. Почитали из одного DAC'a, занесли через другой, еще что-то изменили через третий, потому под конец бац - завершили транзакцию во всех трех объектах. Хотя и при этом мы не гарантированы от блокировок, даже в самом тривиальном случае монопольного доступа к данным - просто потому что используем три раздельные соединения. Причем это как мина замедленного действия, она может рвануть, когда этого совсем не ждешь. Например, добавили какой-нибудь триггер, и те изменения из различных DAC'ов, что раньше происходили изолированно, теперь будут конфликтовать за общий ресурс. Или, скажем, перешли на другую СУБД, а у нее другая стратегия или уровень избирательности блокировок.

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

Но допустим такая задача перед нами не стоит, и мы можем считать, чтом имеем СУБД в монопольное владение. Почему все-таки нехорошо надеяться на finalize() как на средство управления жизненным циклом соединения?

Тут все зависит от модели использования DAC'ов: что инициирует из создание, какова их область видимости и как долго они должны жить.

Если это синглтоны (Singletons), глобальные в масштабах всего приложения, то, казалось бы, ситуация под контролем: мы всегда знаем, сколько соединений у нас открыто - по числу DAC'ов. Но тут нас подстерегает другая ловушка. Если есть хоть малейшая вероятность, что методы доступа к данным будут вызываться из более чем одного потока, то рано или поздно произойдет ситуация, когда фиксация или откат, инициированные из одного потока, приведут к совершенно незапланированным фиксации/откату в незавершенной транзакции, выполняющейся в другом потоке. Почему? Да потому что соединение, которым владеет DAC, всего одно (по недалекому замыслу разработчика), и все запросы на доступ к данным посредством этого класса вынуждены использовать это единственное соединение.

Если же это не синглтоны, а создаются динамически по мере необходимости, то тут мы отдаем себя целиком на милость прикладных разработчиков, потому что если они неаккуратно обращаются с экземплярами DAC'ов и не отпускают ссылки на них (например, вследствие непродуманной стратегии обработки ошибок), то до finalize() дело может никогда и не дойти. Как результат - рано или поздно исчерпание лимита открытых соединений.

Ну вот, а теперь, когда мы разобрались с тем, как делать не надо, закономерно возникает вопрос, а как же все-таки делать правильно. Вопрос на самом деле нетривиальный и однозначного ответа не имеет, потому что многое тут зависит от способа представления датабазных данных в приложении и используемых для этого средств (типа ORM или прямой доступ к данным или EntityBeans, и т. д.). Но я все-таки постараюсь описать один из лучших, на мой взгляд, общих подходов к решению вопроса.

Прежде всего, нужно понять одну простую вещь: доступ к данным не должен быть хаотичным. Мы не можем просто по прихоти взять и доступиться к какой-то таблице. Если мы хотим нашему приложению долгой и счастливой жизни, мы должны осознать, что все операции по работе с данными должны следовать принципу ACID - атомарность, целостность, изолированность и долговечность. В соответствии с эти принципом можно сформулировать примерный цикл выполнения одной целостной логической операции. Прошу обратить внимание, что соединение мы используем одно на всю операцию и передаем его в каждый метод доступа к данным - тем самым мы обеспечиваем полный контроль за состоянием транзакции:

Код


public void doSomeStuff(int someID) throws SQLException, ApplicationException
{
  try
  {
    Connection con = connectionManager.getConnection();

    // тут выполняется прикладная логика операции
    List list = dacProfiles.getSomeProfiles(con, someID);
    int count = dacProfiles.updateLocalProfiles(con, list);
    Profile profile = dacProfiles.getMostRecentProfile(con, someID);
    dacAccounts.doubleBalance(con, profile);
    // конец прикладной логики

    con.commit();
  }
  // тут жизненно важно ловить _все_ исключения, чтобы корректно сделать откат
  catch (Exception e)
  {
    if (con != null)
    {
      try
      {
        con.rollback();
        // после этого нам нужно пробросить исключение наверх, но мы не можем
        // сделать этого в общем виде, поэтому приходится его во что-нибудь завернуть:
        // или в SQLException, или в RuntimeException. Хорошо также все датабазные
        // операции объявлять как выбрасывающие какой-нибудь application-level
        // exception и заворачивать в него
        throw new ApplicationException(e);
      }
        catch (SQLException e1)
      {
        logger.error("Could not rollback transaction", e1);
        // если это достаточно общий метод, то он не должен знать, как поступать
        // в подобной ситуации, поэтому можно выбросить специальное исключение
        throw new RollbackFailedTransaction(e1);
      }
    {
  }
  finally
  {
    if (con != null)
    {
      try
      {
        con.close()
      }
       catch (SQLException e2)
      {
        // тут особенно ничего не поделаешь, так что можно ничего и не выбрасывать,
        // тем более что в вызывающий поток оно все равно не попадет.
        logger.error("Could not close connection", e2);
      }
    {
  }
}


Подчеркиваю, аналогичным образом должны быть оформлены все высокоуровневые логические операции (которым, например, в терминах EJB соответствуют методы SessionBean'а, в веб приложении - запросы, а в веб-сервисе - отдельные сервисы). Но поскольку повторять раз за разом один и тот же громоздкий код - занятие утомительное и, более того, чреватое ошибками, то гораздо лучше оформить это дело в единственном экземпляре. Так сама собой всплывает идея фреймворка, основой которого является понятие Worker'а.

Код

public abstract class AbstractWorker
{
  public void doWork()
  {
    // тут идет практически один в один код из предыдущего фрагмента,
    // с той разницей, что вместо последовательности конкретных действий
    // по доступу к данным мы оставляем эту заботу конкретным реализациям
    doActualWork();
  }

  protected abstract void doActualWork();
}


После этого реализация прикладных методов сводится к написанию примерно такого кода (скопированр из первого примера):

Код

public class SomeStuffWorker extends AbstractWorker
{
  public void doActualWork() throws SQLException, ApplicationException
  {
    // тут выполняется прикладная логика операции
    List list = dacProfiles.getSomeProfiles(con, someID);
    int count = dacProfiles.updateLocalProfiles(con, list);
    Profile profile = dacProfiles.getMostRecentProfile(con, someID);
    dacAccounts.doubleBalance(con, profile);
    // конец прикладной логики

  }
}


Фсе! Дальше можно смело отдавать все это кодерам без опасения, что они смогут чего-нибудь по-крупному напортить.

Разумеется, это не единственный, не финальный и не обязательно лучший фреймворк для всех классов задач, но он примерно в восемьдесят тысяч раз лучше того, с которого мы начинали рассмотрение smile

Фу-х, аж вспотел, блин smile

PM WWW   Вверх
batigoal
Дата 5.5.2005, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



Цитата(Stampede @ 5.5.2005, 01:45)
Фу-х, аж вспотел, блин

А уж я-то как...
Спасибо! smile


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
Гость_junior
Дата 5.5.2005, 12:47 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











у меня NetBeans 3.6
  Вверх
Се ля ви
Дата 5.5.2005, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 8
Всего: 127



Цитата
у меня NetBeans 3.6

Поставь 4-ю - в ней ввели понятие подключаемых библиотек уже...


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
LSD
Дата 5.5.2005, 21:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата
Да, ошибка на стадии компиляции.

Было бы неплохо знать, что за ошибка, т.к. Class.forName("oracle.jdbc.driver.OracleDriver") при компиляции не вызывает cannot resolve symbol независимо от того какие библиотеки подключенны.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Се ля ви
Дата 6.5.2005, 14:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java/SOAрхитектор
****


Профиль
Группа: Модератор
Сообщений: 2016
Регистрация: 5.6.2004
Где: place without tim e and space

Репутация: 8
Всего: 127



Цитата(Stampede @ 5.5.2005, 00:45)
вдруг мы захотим добавить еще один метод доступа с другим SQL запросом? Тогда придется постоянно пересоздавать Connection.createStatement("select blah-bla-blah"). Так и будем все время выдергивать соединение из стейтмента?

Stampede, ессно, что если нам часто нужен объект, для работы с ним лучше хранить постоянную ссылку на него, если же он нам нужен редко - то зачем плодить переменные, если можно иногда его вытаскивать?.. Я согласен почти со всем, что ты написал, но не будь таким жестким - задачи-то разные бывают smile

Тем более, ну ведь это из серии "что в лоб, что полбу" - всё равно всё у нас на уровне ссылок и операций с объектами. smile


--------------------
  )
 (
[_])
проф. блог

Кролики думали, что занимаются любовью, а на самом деле их просто разводили...
PM MAIL WWW Skype GTalk   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1332 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.