![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
Се ля ви |
|
|||
![]() Java/SOAрхитектор ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2016 Регистрация: 5.6.2004 Где: place without tim e and space Репутация: 8 Всего: 127 |
Гость_junior
Так, погоди, ты какой вариант используешь? Я чего-то не пойму - у тебя ошибка на уровне компиляции кода или на уровне выполнения? В том варианте, который дал я проблемы "КлассНотФоунд" не должно быть. Кароче, компилятор у тебя драйвер оракла не видит, или JRE? Что бы увидел компилятор, надо его в библиотеку грузить - просто так jre/lib.ext не поможет. Она годится на уровне выполнения, если будешь подгружать драйвер выражением
Добавлено @ 11:03 если же ты import`ируешь класс явно - то он должен быть в составе библиотеки твоего проекта... -------------------- |
|||
|
||||
Гость_junior |
|
||||
Unregistered |
Да, ошибка на стадии компиляции.
Как узнать значение подмененной переменной? Спасибо |
||||
|
|||||
Се ля ви |
|
|||
![]() Java/SOAрхитектор ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2016 Регистрация: 5.6.2004 Где: place without tim e and space Репутация: 8 Всего: 127 |
Гость_junior, NetBeans у тебя какой версии?
-------------------- |
|||
|
||||
Stampede |
|
||||||||||
![]() Гносеолог ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 963 Регистрация: 25.4.2005 Где: Calgary, Alberta, Canada Репутация: 24 Всего: 144 |
Объясняю ![]() Вот у Се ля ви приведенный им в качестве примера класс реализует некий метод доступа к датабазным данным. Причем у него вообще наличествует только один такой метод и соответственно одна переменная типа 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 - атомарность, целостность, изолированность и долговечность. В соответствии с эти принципом можно сформулировать примерный цикл выполнения одной целостной логической операции. Прошу обратить внимание, что соединение мы используем одно на всю операцию и передаем его в каждый метод доступа к данным - тем самым мы обеспечиваем полный контроль за состоянием транзакции:
Подчеркиваю, аналогичным образом должны быть оформлены все высокоуровневые логические операции (которым, например, в терминах EJB соответствуют методы SessionBean'а, в веб приложении - запросы, а в веб-сервисе - отдельные сервисы). Но поскольку повторять раз за разом один и тот же громоздкий код - занятие утомительное и, более того, чреватое ошибками, то гораздо лучше оформить это дело в единственном экземпляре. Так сама собой всплывает идея фреймворка, основой которого является понятие Worker'а.
После этого реализация прикладных методов сводится к написанию примерно такого кода (скопированр из первого примера):
Фсе! Дальше можно смело отдавать все это кодерам без опасения, что они смогут чего-нибудь по-крупному напортить. Разумеется, это не единственный, не финальный и не обязательно лучший фреймворк для всех классов задач, но он примерно в восемьдесят тысяч раз лучше того, с которого мы начинали рассмотрение ![]() Фу-х, аж вспотел, блин ![]() |
||||||||||
|
|||||||||||
batigoal |
|
|||
![]() Нелетучий Мыш ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6423 Регистрация: 28.12.2004 Где: Санктъ-Петербургъ Репутация: 24 Всего: 151 |
А уж я-то как... Спасибо! ![]() -------------------- "Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли) ЖоржЖЖ |
|||
|
||||
Гость_junior |
|
|||
Unregistered |
у меня NetBeans 3.6
|
|||
|
||||
Се ля ви |
|
|||
![]() Java/SOAрхитектор ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2016 Регистрация: 5.6.2004 Где: place without tim e and space Репутация: 8 Всего: 127 |
Поставь 4-ю - в ней ввели понятие подключаемых библиотек уже... -------------------- |
|||
|
||||
LSD |
|
|||
![]() 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. |
|||
|
||||
Се ля ви |
|
|||
![]() Java/SOAрхитектор ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2016 Регистрация: 5.6.2004 Где: place without tim e and space Репутация: 8 Всего: 127 |
Stampede, ессно, что если нам часто нужен объект, для работы с ним лучше хранить постоянную ссылку на него, если же он нам нужен редко - то зачем плодить переменные, если можно иногда его вытаскивать?.. Я согласен почти со всем, что ты написал, но не будь таким жестким - задачи-то разные бывают ![]() Тем более, ну ведь это из серии "что в лоб, что полбу" - всё равно всё у нас на уровне ссылок и операций с объектами. ![]() -------------------- |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |