Xpoint
   [напомнить пароль]

Проблемы с сессией и cookies

Метки: [без меток]
2006-05-16 14:25:09 [обр] teho[досье]

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

Работаю только с .jsp
Например, на главной index.jsp странице есть форма авторизации.
Если человек попал на неё в первый раз, я создаю сразу же сессию так:

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection cn = null;
сn = DriverManager.getConnection("jdbc:odbc:db", "", "");
session.putValue("connect", cn);

Чтобы на других .jsp каждый раз не делать коннект, я его получаю так: Connection cn = (Connection)session.getValue("connect");

Это вроде работает, правда с переменным успехом.

Если человек прошел регистрацию или авторизировался на главной, создаю для него cookie так:

Cookie cookie = new Cookie("idclient", idclient); //idclient - id клиента, который хранится в БД
cookie.setMaxAge(3600);
response.addCookie(cookie);

На др. страницах, чтобы следить за клиентом и вытаскивать значение idclient, я делаю так:

Cookie[] cookies = request.getCookies();
if(cookies == null) out.println("Cookie почему-то не обнаружен, повторите авторизацию.");
for(int i=0; i<cookies.length;i++) {
Cookie thisCookie = cookies[i];
if(thisCookie.getName().compareTo("idclient") == 0) {
idclient = thisCookie.getValue();
}
}

Потом полученный idclient использую в запросах.

Куки создаются и в них помещается значение idclient, все норм. А вот с сессией коннекта какие-то проблемы... Иногда на др. .jsp страницах не получается вытащить коннект и запросы не выполняются. Причем если сессия одна открыта, человек, который одновременно подконнектился, но не авторизировался и не зарегился, может покупать под id человека, который сейчас уже в магазине...

Ради проверки, я убрал сессию и оставил только куки, а на каждой странице создавал коннект и убивал его после завершения запросов. Так все прекрасно работает, но так делать - бред.

Может подскажите, как разобраться с этим... Уже всю голову сломал.

спустя 17 минут [обр] Данбала(2/63)[досье]
  1. seesion.setAttribute(strName, objValue), session.getAttribute(strName).
  2. Зачем вся эта возня с Cookie? После успешной аутентификации кладите в session объект UserView, описывающий пользователя, и работайте с ним. На других страницах. Например:
UserView userView = (UserView)session.getAttribute("userView");
if (userView.getUserID().equals(someOtherID)){
    //...
}
  1. Какой таймаут у connection с БД? В смысле, не истекает ли он слишком быстро (быстрее сессии)?
спустя 31 минуту [обр] Данбала(2/63)[досье]
  1. Какой смысл в том, чтобы на каждую сессию создавать Connection?
Лучше работать с контекстом:
getServletContext().setAttribute("connection", connection);
...
Connection conn = (Connection)getServletContext().getAttribute("connection");
спустя 14 минут [обр] GRAy(14/259)[досье]
teho[досье] Вы случаем не хотите ли сохранять объект connection между запросами к серверу? Плохая идея. Connection слишком сложно устроен и зависит от реализации конкретного драйвера конкретного поставщика СУБД - его нельзя класть в сессию в надежде что он гарантировано восстановится в следующий раз, это целиком определяется вашим контейнером. Если контейнер использует какой-то failover (а какой нет?) механизм и/или работает в кластере это означает, что сессии должны сериализовываться в поток и/или какое-нибудь хранилище, и все объекты, которые в ней хранятся тоже должны быть сериализуемыми. Для connection это невыполнимое условие в общем случае. Поэтому и придумали пулы connection`ов и DataSourc`ы. Для контекстов различных действуют те же ограничения. Даже если всё вышесказанное к вам не относится (ваш сервер не делает failover и не работает в кластере) - хранение connection`ов в сессии или в контексте, это не threadsafe и прямой путь к deadlock`ам и утечкам памяти (при большом кол-ве пользователей вы на каждого создадите тяжеловесный connection, который мало того что сожрёт память, так и ещё базу данных может завалить).
спустя 6 минут [обр] Данбала(2/63)[досье]

GRAy[досье]
Хранение Connection в контексте и на каждого пользователя? Что вы имеете в виду? Воображение рисует что-то жуткое :) Если есть ConnectionPool, то лучше, конечно, положить в контекст его, а не сам Connection.

А что такое fileover механизм?

спустя 1 час 17 минут [обр] GRAy(14/259)[досье]
Не fileover, а failover - восстановление после "падения". Контейнер гарантирует, что даже если по каким-либо причинам он рухнул, пользовательские данные не будут потеряны. К пользовательским данным как раз относятся сессии.
Насчёт создания connection`а для каждого пользователя это я погорячился - не понял что вы имели ввиду использование одного connection`а всеми потоками выполнения сервлета, но хранить connection в servletContext это ещё хуже чем в сессии, т.к. гарантировано приведёт к ошибкам синхронизации при обращении к базе данных (вернее никто вам не даёт гарантии, что не приведёт :) если только вы не сделаете synchronized, но в этом случае будет "бутылочное горлышко").
спустя 25 минут [обр] Данбала(2/63)[досье]
GRAy[досье]
С failover понятно. Я и разрабатывал сам, и участвовал в достаточном количестве проектов, но ни в одном из них такой необходимости не было. Разработка велась из расчета, что сервер не упадет. И он не падал. То есть падал, но раз в несколько лет, и, если такое случалось, то это была такая катастрофа, что не до данных пользователя :) Впрочем, может, мне не повезло в чем-то таком, супернадежном, поучаствовать.
  1. А какие могут быть ошибки синхронизации? БД вроде транзакции поддерживает, верно? IMHO, наиболее часто встречающаяся реализация это, когда есть ConnectionPool в виде singleton-а (что в данном контексте то же самое, что и атрибут ServletContext-а), из которого по необходимости дергаются соединения. И все прекрасно работает. Опять же, это я и сам делал, и видел чужие реализации. Или я чего-то не понял?
спустя 40 минут [обр] GRAy(14/259)[досье]
Данбала[досье] Это не столько ошибки синхронизации самой БД, сколько обычные ошибки многопотокового доступа к одному и тому же объекту. Всё-таки connection полученный из ConnectionPool`а и connection полученный из драйвера и сохранённый в атрибуте servletContext`а это разные вещи (даже имплементирующие классы разные). ConnectionPool помимо того что просто хранит коллекцию соединений ещё как раз и реализует невозможность обращения из разных потоков к одному и тому-же объекту connection (хотя никак не может вам помешать это ограничение обойти). Т.е. после того как он выдал один из имеющихся connection`ов, пока его не вернут туда явно или по таймауту, он никому больше эту ссылку не даст. Даже если одновременное обращение из разных потоков не вызовет проблем при работе методов объекта Connection, это может привести к ошибкам БД, например один поток вставляет записи, а другой, через этот же connection делает rollback, и всё, заметьте в рамках одной транзакции (которую, кстати, открыл третий поток, а четвёртый, вдруг, захотел закрыть раньше времени).
спустя 19 минут [обр] Данбала(2/63)[досье]
Т.е. после того как он выдал один из имеющихся connection`ов, пока его не вернут туда явно или по таймауту, он никому больше эту ссылку не даст.

Ну а ServletContext-то чем хуже?

Connection conn = (Connection)getServletContext().getAttribute("connection");
if (conn == null || conn.isClosed()){
    conn = DriverManager.getConnection("...");
    getServletContext().setAttribute("connection", conn);
}

И вперед!

один поток вставляет записи, а другой, через этот же connection делает rollback, и всё, заметьте в рамках одной транзакции (которую, кстати, открыл третий поток, а четвёртый, вдруг, захотел закрыть раньше времени)

Ну это уже вопрос проектирования. Кто станет в одном сервлете читать, в другом закрывать и пр.? Кроме того, если мне захочется так с ума посходить, то и ConnectionPool не спасет.

Я это все к тому, что у автора по всей видимости простая задача. И если нет пула, то можно и так, как я предлагаю. Ну, а вобщем случае можно, конечно, много чего предложить помимо Connection Pool.

спустя 6 минут [обр] GRAy(14/259)[досье]
Ну как же так.
Вот у вас один поток сделал себе connection положил его в servletContext и начал с ним работать, а чуть позже (первый ещё чем-то занят) другой поток спросил у servletContext`а - а есть ли у тебя connection, на что тот честно отдал ему имеющийся у него connection созданый ранее первым потоком. Оба потока имеют теперь указатели на один и тот же объект, и оба могут с ним захотеть сделать вещи друг другу противоречащие (первый поток закончил выполнение и закрыл connection - что делать второму потоку?).
спустя 1 минуту [обр] teho[досье]

Данбала, GRAy, спасибо за ответы.

С connections я уже определился, буду использовать пул для своего сервера.

Данбала,
если можно, можете рассказать поподробнее, как создать этот объект UserView?.. Только начинающий, сорри...

После аутентификации, на руках у нас есть id клиента, который потом будет использоваться в запросах на др. jsp страницах... Так вот его (только) и нужно положить в сессию, как я понимаю. Т.е. должен вызываться метод объекта UserView, который бы сохранял внутри себя этот id, а потом кладем этот объект в сессию, так? Если не трудно, можете ткнуть носом в какой-нибудь пример, где в рамках .jsp синтаксиса можно описать объект... Хотя можно и на сервлет.

спустя 2 минуты [обр] Данбала(2/63)[досье]
А зачем его вообще закрывать? Попросили connection, запросили, например, список товаров, показали его на сайте. И все. Другой сервлет делает то же самое. Connection при этом вообще не закрывается приложением. Если нужно, пусть закрывается самой БД по таймауту.
спустя 12 минут [обр] Данбала(2/63)[досье]
 Т.е. должен вызываться метод объекта UserView, который бы сохранял внутри себя этот id, а потом кладем этот объект в сессию, так?
class UserView {
    private String id;
    private String name;

    public UserView(id){
        this.id = id;
    }
   
    public getName(){
        return name;
    }

    public setName(String name){
        this.name = name;
    }
}

name для примера.
В JSP :

 Authentificator auth = Authentificator.getInstance();
    String id = auth.authentificate(name, password);
    if (id != null) {
        UserView userView = new UserView(id);
        userView.setName("teho");
    }
    HttpSession session = request.getSession().setAttribute("userView", userView);

Ну, например, так. В заголовке jsp проимпортируйте UserView.

спустя 5 минут [обр] GRAy(14/259)[досье]
Данбала[досье] Закрытие я привёл в качестве примера. Может быть более тонкая ситуация связанная с внутренней организацией доступа к БД например. Откуда вы знаете, что драйвер правильно сработает если к нему одновременно или почти одновременно придут два запроса от одного и того-же объекта connection? Как разрешить ситуацию с двумя одновременно идущими транзакциями по одному и тому-же connection`у (как их открыть и как их закрыть)? Что делать если один запрос привёл БД в неконсистентное состояние, а другой в этот же момент попытался сделать commit? Да мало ли что ещё. Самое опасное в этих всех ошибках, что они проявляются ой-как нерегулярно. И сервер падает, и данные теряются, и пользователь видит ошибки там, где их, казалось бы и быть не может. Весь этот балаган с ConnectionPool`ами и прочими плясками вокруг Connection`ов не зря появился. Будь оно так просто как вы описываете - нафига тогда вообще это нужно?
спустя 6 минут [обр] 30-ый(59/584)[досье]
Данбала[досье], вы точно не видите ошибки в вашем подходе? Перечитайте еще раз - это же очевидно.
спустя 59 секунд [обр] Данбала(2/63)[досье]

GRAy[досье]

Может быть более тонкая ситуация связанная

и

нафига тогда вообще это нужно

Я же написал, для простой задачи.

Откуда вы знаете, что драйвер правильно сработает если к нему одновременно или почти одновременно придут два запроса от одного и того-же объекта connection?

Из стандарта JDBC. Оба запроса на чтение! Не могу дать ссылку, не помню, где видел.
Остальные ситуации не попадают под категорию простых задач, так? К тому же, я привел пример такой задачи.

спустя 2 минуты [обр] Данбала(2/63)[досье]
30-ый[досье]
Для примерной постановки задачи, которую я привел, — нет, не вижу. Хотя, не стану спорить, так я делал только для отладки, когда подключался один. Потом это код не работал.
спустя 8 минут [обр] GRAy(14/259)[досье]

Данбала[досье]

Из стандарта JDBC.

Стандарт JDBC никак не определяет работу драйвера на стороне БД - он определяет только интерфейсы.
Да и сложность задачи тут вообще не при чём, это может в обычной анкете происходить - поверьте, не раз наблюдал. То что вы рекомендуете - шапкозакидательский подход чреватый трудноуловимыми runtime ошибками. Я всего-лишь хотел предостеречь от него teho[досье].

Для примерной постановки задачи, которую я привел, — нет, не вижу. Хотя, не стану спорить, так я делал только для отладки, когда подключался один. Потом это код не работал.

Так объяснили-бы что это не production решение вопроса, или вы хотели бедному teho[досье] свинью такую подложить? ;))

спустя 1 час 41 минуту [обр] Данбала(2/63)[досье]

GRAy[досье]
Вам нужны прокшн-постановки задач, где то, что я описал верно? Если хотите, могу шапкозакидать :| Вот только потренируюсь немного с разными шапками.

Что касается "обычной анкеты". В третий и последний раз повторяю: ВСЕ ЗАПРОСЫ НА ЧТЕНИЕ.

спустя 46 минут [обр] GRAy(14/259)[досье]
 В третий и последний раз повторяю: ВСЕ ЗАПРОСЫ НА ЧТЕНИЕ.
??? что-то я одного раза недосчитался. На чтение запросы или на запись - значения не имеет.
Вы предлагаете небезопасное решение (сами это признаёте), при наличии ни в чём ему не проигрывающего безопасного решения. То что на свете существует масса случаев где можно положившись на авось реализовать доступ к БД так как вы описываете и ничего не будет ломаться N-лет, не умаляет того факта, что ошибка случится может, вы об этом знаете и ничего не хотите сделать, чтобы этого не произошло. Вам самому приятно работать с софтом написанным людьми исповедующими такой подход?
спустя 14 минут [обр] Данбала(2/63)[досье]

GRAy[досье]

??? что-то я одного раза недосчитался.
  1. "Попросили connection, запросили, например, список товаров, показали его на сайте."
  2. "Оба запроса на чтение!"
  3. И последний.

Можете пересчитать.

сами это признаёте

Где?!

То что на свете существует масса случаев где можно положившись на авось реализовать доступ к БД так как вы описываете и ничего не будет ломаться N-лет, не умаляет того факта, что ошибка случится может, вы об этом знаете и ничего не хотите сделать, чтобы этого не произошло.

Мало того, что я шапками кидаюсь, так еще и полагаюсь на авось?! Где, черт возьми, я это предлагал?!

Вне зависмости от того, чего вы там не досчитались, признаете ли вы, что хранение Connection в ServletContext-е при том условии, что все запросы на чтение, не только легально, но и вполне допустимо? Если нет:

  1. Аргуметнируйте.
  2. Хотите ли вы такую постановку задачи, при котрой описанный мной подход будет единственным верным решением?

PS Пожелание: если беретесь комментировать посты, то комментируйте все их части, а не особо понравившиеся.

спустя 24 минуты [обр] 30-ый(59/584)[досье]

Данбала[досье], вы защищаете какуюто нелепость.

Это и серии того, что 2 плюс 2 равно пяти при условии, что нас устраивает погрешность в 25%.

спустя 12 минут [обр] Данбала(2/63)[досье]

30-ый[досье]
Неужели вы не видите? Хорошо, значит, не видите. Тогда, вам тот же вопрос:

Хотите ли вы такую постановку задачи, при котрой описанный мной подход будет единственным верным решением?

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

спустя 16 минут [обр] 30-ый(59/584)[досье]
хочу! Только просьба эти не предлагать:
- нет под рукой необходимых библиотек.
- есть только одна клиентская лицензия к серверу.
- глючный драйвер сыпется при открытии нескольких коннекшенов
- нам требуется некая целостность базы на сервере без поддержки транзакций.
я их сам только что из пальца высосал :-)
спустя 15 минут [обр] Данбала(2/63)[досье]

30-ый[досье]

Только просьба эти не предлагать:

Боже! За кого вы меня принимаете, в конце концов?

На самом деле, все очень просто: Петя отвечает за СУБД (CRUD-ит над ним, аутентифицирует, авторизует, предоставляет внутренним пользователям организации интерфейс для управления контентом этой СУБД и т. д. (набивают данные)), а Вася делает всего-навсего Internet-доступ к базе, т. е. просто показывает то ее содержимое на сайте, которое ему разрешил показываеть Петя. Вот и все. У Васи есть права только на чтение, да и то не на все подряд. То, что он не может прочитать, он выяснит либо непосредсвенно у Пети, ли во время отладки, когда ему исключения про доступ посыпятся. Просто отделите Internet-представление данных в БД от их внутреннией (внутри организации, которой они принадлежат, внутри ее сети) от их Intranet-представления (www), пусть это будут два приложения. После этого отнимите у Васи всякие hibernate- и иже с ним прослойки, и вы получите как раз то, что я обещал.

ЗЫ Не так давно я сам был таким Васей.

спустя 23 минуты [обр] 30-ый(59/584)[досье]

И против вашего решение здесь говорит очень много факторов. Особенность сайта в том, что к нему могут одновременно обращаться много пользователей.

У вас же только один коннекшен. А я не помню, чтобы коннешены были thread-safe. А значит вам придется сериализовывать все обращения. Это довольно быстро надоест и мы получим просто сериализованные запросы... что немедленно отразится на производительности.

Даже если мы и сериализуем бережно все обращения (или даже найдем где-то thread-safe коннекшен), наше решение все равно будет тормозить на обращениях к базе.

В частности, если у нас у сети большая латентность (сложный Firewall с анализатором траффика), вся наша конструкция умрет очень быстро. Даже если сеть очень быстрая, а SQL-сервер очень мощный, мы не сможем передавать запросы чаще, чем время отклика.

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

спустя 25 минут [обр] GRAy(14/259)[досье]

<В сторону>Вот развели флейм на пустом месте ;)</В сторону>
30-ый[досье] Вы хотели сказать не сериализуем а синхронизируем наверное?
Данбала[досье]

Где?!

Вот:

Хотя, не стану спорить, так я делал только для отладки, когда подключался один. Потом это код не работал.

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

Вне зависмости от того, чего вы там не досчитались, признаете ли вы, что хранение Connection в ServletContext-е при том условии, что все запросы на чтение, не только легально, но и вполне допустимо? Если нет:
  1. Аргументируйте.

Аргументирую уже на протяжении всего треда. Небезопасно с точки зрения thread-safe. Какие могут быть проблемы? Да любые, и даже каждый раз разные ;) и ни одну из них вы не сможете исправить потому что драйвер БД писали не вы (скорее всего).
Hibernate и прочее тут вообще не ночевали. Как по вашему работает Hibernate с базой? Через какие-то волшебные драйвера которые сами за всем следят? Ну я не верю что вы такой наивный ;) Тот же самый JDBC и те же самые ConnectionPool`ы и DataSource`ы. В описаной вами ситуации ничто вам не мешает организовать доступ к БД из приложения так, как вам заблагорассудится, и почему при этом надо выбирать метод с большой вероятностью приводящий к ошибкам, мне, извините, так и не стало понятно. И Петя вам ничем не поможет, а может даже по башке настучит, за то что база падать будет из-за ваших кривых обращений.

спустя 1 час 30 минут [обр] 30-ый(59/584)[досье]
Да, конечно "синхронизируем". Меня сбил тип уровня изоляции транзакций "SERIALIZABLE", который по смыслу имеет много общего с джавной "synchronize"... ближе к ночи умные слова путаются. :-)
спустя 8 часов [обр] Данбала(2/63)[досье]

GRAy[досье]

или я не правильно вас понял...

Нет, не неправильно. Извращенно. Вы извращаете смысл сказанного так, чтобы у вас была возможность хоть что-нибудь авторитетно заявить.

что вы не зная наверняка как работает драйвер отказываетесь (и доказываете, что оно "лучше") от архитектурно более безопасного решения от этого самого драйвера не зависящего в принципе.

При чем тут драйвер? Или вы способны предъявить решение, которое взаимодействуя с базой, никак не использует драйвер?

Аргументирую уже на протяжении всего треда.

Ничего подобного, вы только утверждаете.

Небезопасно с точки зрения thread-safe.

Почему? Это утверждение, а не аргумент.

Какие могут быть проблемы? Да любые, и даже каждый раз разные ;) и ни одну из них вы не сможете исправить потому что драйвер БД писали не вы (скорее всего).

Почему? Это утверждение, а не аргумент. Как вы можете быть уверены, что select * from mytable; сработает верно, а вдруг драйвер кривой, и вы получите полкило всякой хрени вместо всех записей?

Hibernate и прочее тут вообще не ночевали.

Типа я просто красивое слово вставил, а вы тут как специалист решили одернуть? Читайте внимательнее: "отнимите у Васи всякие hibernate- и иже с ним прослойки".
Ночевал, ночует и ночевать будет.

Как по вашему работает Hibernate с базой?

Не по моему, просто работает.

Через какие-то волшебные драйвера которые сами за всем следят?

У вас жара случайно нет? Какие еще волшебные драйвера? Конечно, через заколдованные! Про драйвера см. выше.

почему при этом надо выбирать метод с большой вероятностью приводящий к ошибкам

Он не приводит к ошибкам.

 И Петя вам ничем не поможет

Жаль, конечно. А вам он тоже не помог? Надеялись на него наверно...

а может даже по башке настучит, за то что база падать будет из-за ваших кривых обращений.

Кому, вам? За ваши кривые обращения? Что ж, учитесь обращаться прямо.

спустя 2 часа 17 минут [обр] GRAy(14/259)[досье]

Данбала[досье] Вот вскипятились. Я нашёл указание в спецификации JDBC где явно сказано что Connection должны быть thread-safe. Вот тут - раздел A.1.6. (хотя реализации не всегда thread-safe, а драйвера не всегда стабильны при большом количестве одновременных обращений). Так что для 90% случаев ваш "простой" метод ничем не хуже "сложного" метода с ConnectionPool`ом.

зы. Большая часть вашего последнего поста - истерика какая-то. Чужое мнение для вас как бельмо в глазу? Берегите нервы. Я пишу в форум не для поднятия самомнения, а для поднятия собственного профессионализма. Большую часть дискуссии я общаюсь с вами а не с автором, и делать громкие заявления по поводу того что я "извращаю смысл сказанного так, чтобы иметь возможность хоть что-то авторитетно заявить" - откровенное хамство с вашей стороны.

спустя 33 минуты [обр] Данбала(2/63)[досье]

GRAy[досье]

откровенное хамство с вашей стороны.

Мой последний пост — это как раз иллюстрация хамства с вашей стороны. А именно "громких заявляний" про шапкозакидательство, кривые обращения и т. п. И "Чужое мнение для вас как бельмо в глазу?" из той же оперы. Откуда вы это взяли? Это я и назвал извращением смысла. Берете откуда-то вопросы, на которое можно "круто" ответить.

К тому же, зачем все эти наезды, если вы все таки признаете, что "Так что для 90% случаев ваш "простой" метод ничем не хуже "сложного" метода с ConnectionPool`ом."?

ЗЫ Ладно, погорячился, прошу прощенья...

ЗЫЫ Не надо этих "90%". 100%.

спустя 16 минут [обр] 30-ый(59/584)[досье]

> зачем все эти наезды, если вы все таки признаете

Потому что GRAy[досье] не поленился найти информацию о том, что Connection'ы должны поддерживать работу из нескольких потоков. Только после этого ваш метод в принциме имеет право на существование. В ваших репликах, Данбала[досье], это почему то подразумевалось как некая мелочь, доказательства которой не требуется.

спустя 8 минут [обр] Данбала(2/63)[досье]

30-ый[досье]

Потому что GRAy не поленился найти информацию о том, что Connection'ы должны поддерживать работу из нескольких потоков.

А я значит поленился? А то, что у меня времени на это не хватило, вам не пришло в голову? И если он не поленился, то имеет право писать вообще что угодно?

В ваших репликах, Данбала, это почему то подразумевалось как некая мелочь, доказательства которой не требуется.

Где это подразумевалось? Я хотел сказать, что при запросах только на чтение все очень просто. И по моему сказал...

спустя 1 час 22 минуты [обр] гоша(0/39)[досье]

Данбала, брось изворачиваться. Облажался - сиди тихо.

GRAy, Родион: можно еще раз на пальцах и медленно, как правельно надо делать.

спустя 20 минут [обр] 30-ый(59/584)[досье]

:-)

Итак, "на пальцах и медленно". В принципе существует много способов куда-то сохранить и потом использовать pool соединений. В принципе и самому написать что-то подобное не так уж сложно.

Думаю наиболее удачное решение - использование встроенного в Tomcat пулинга, который в свою очередь использует pool-коннекшенов из Apache-Commons.

Для этого нужно зарегистрировать соответсвующие соединения в томкате и запросить их потом через JNDI. Делается так:

В каталоге /META-INF вашего приложения создаем файл context.xml. Вид примерно следующий:

<Context path="/epd">
  <Resource name="jdbc/epd.admin" 
            auth="Container"
            type="javax.sql.DataSource" 
            username="www_epd_admin" 
            password="***"
            driverClassName="org.postgresql.Driver" 
            url="jdbc:postgresql://eupdsrv.db:5432/projekt.epd"
            maxActive="4" 
            maxIdle="2"/>
</Context>

В файле web.xml вашего приложения добавляем следующее:

    <resource-ref>
      <res-ref-name>jdbc/epd.admin</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
    </resource-ref>

Теперь нужный коннекшен мы получаем следующим образом:

    public static Connection getConnection() throws SQLException {
        try {
            String jndiName = "jdbc/epd.admin";
            Context initCtx = new InitialContext();
            Context envCtx = (Context) initCtx.lookup("java:comp/env");
            Object obj = envCtx.lookup(jndiName);
            DataSource ds = (DataSource)obj;
            return ds.getConnection();
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }

Используем коннекшен как обычно... не забывая закрывать:

    Connection conn = Config.getConnection();
    try {
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery(s);
        ....
        rs.close();
        st.close();
    } finally {
        conn.close();
    }

Ссылки:
http://jakarta.apache.org/commons/dbcp
http://tomcat.apache.org/tomca......datasource-examples-howto.html

спустя 2 часа 48 минут [обр] teho[досье]

Ух, ну и написали!.. Сейчас почитаю.
Данбала, спасибо за пример с UserView, понял.

Rodion Alukhanov,
как раз увидел Ваш последний пост... Правда уже второй день сижу разбираюсь тут (http://tomcat.apache.org/tomca......datasource-examples-howto.html), и вот возник вопрос сразу... URL, который указывается в server.xml (у Вас в context.xml)...

<!-- url: The JDBC connection url for connecting to your MySQL dB.
         The autoReconnect=true argument to the url makes sure that the
         mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
         connection. mysqld by default closes idle connections after 8 hours.
         -->

Это с томкэтовского сайта, впринципе понятно для чего он нужен, но если я использую драйвер sun.jdbc.odbc.JdbcOdbcDriver, то в url по идее я могу указать скажем "http://www.bla.ru/reconnect.jsp?=connect_to_db=true" или надо писать что-то типа такого: jdbc:odbc://localhost:8080/reconnect.jsp?=connect_to_db=true"?

спустя 4 минуты [обр] teho[досье]
Да, а в reconnect.jsp что нужно собственно указывать, чтобы драйвер реконнектнулся? Или есть специальный url, который бы сделал reconnect сановского драйвера?
спустя 8 минут [обр] 30-ый(59/584)[досье]
  1. Я предпочитаю без необходимости не лазить в конфиги сервера. Уж очень часто сервера приходится обновлять. Каждый раз исправлять - терпения не непасешься. Соответсвенно рекомендую context.xml.
  1. URL для подключения к серверу - вещь специфическая для драйвера. К двайверу обычно прилагается инструкция, как этот URL писать. К вашей структуре JSP (и к вашему Web-серверу вообще) этот URL никакого отношения не имеет. Если не ошибаюсь, для ODBC-Bridge строка выглядит так "jdbc:odbc:<имя_odbc>". Дайте поиск по "JdbcOdbcDriver connection string".
спустя 12 минут [обр] teho[досье]
Нашел на сайте sun.com
Действительно, Вы правы jdbc:odbc:<имя_odbc>". Спасип.
спустя 4 минуты [обр] GRAy(14/259)[досье]
teho[досье] Кстати, поиск в инете (по вопросу, насчёт которого мы поспорили с Данбала[досье]) меня приводил на форумы, в которых обсуждалась проблемы многопоточного доступа именно у sun`вского jdbcOdbc драйвера. Будьте внимательны ;) хотя там топики были старые, может сейчас всё лучше.
спустя 18 часов [обр] teho[досье]

В общем ничего не заработало... :-)
Что сделал:
В server.xml(знаю, что плохо, но пока тестирую, оставлю так) между <Host> ... </Host> вставляю контекст:

<Context path="/myApp" docBase="myApp"
         debug="5" reloadable="true" crossContext="true">

        <Resource name="aspodb" auth="Container" type="javax.sql.DataSource"
                  url="jdbc:odbc:aspodb" username="teho" password="ain1985"
                  driverClassName="sun.jdbc.odbc.JdbcOdbcDriver"
                  maxActive="100" maxIdle="10" maxWait="10000"
                  removeAbandoned="true" removeAbandonedTimeout="60"/>
</Context>

Далее, в WEB-INF/web.xml пишу:

<description>My app mssql test</description>
<resource-ref>
  <description>DB Connection</description>
  <res-ref-name>jdbc/aspodb</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

Далее беру одну свою .jsp, в которой есть работающий коннект и запрос к бд.
Заменяю там создание коннекта к БД на:

Context initContext = new InitialContext();
Context envContext  = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/aspodb");
if ( ds == null ) {
  throw new Exception("Data source not found!");
}
Connection cn = ds.getConnection();

Далее беру свою test.jsp, создаю папку в webapps\ROOT\myapp и кладу в неё...

Тест: http://127.0.0.1:8080/myapp/test.jsp и гора ошибок:
Context cannot be resolved to a type
InitialContext cannot be resolved to a type
DataSource cannot be resolved to a type

Я грешу, что в .jsp я не сделал какого-то импорта библиотеки <%@page import="java.*... Но какого?
Может кто-нибудь подскажет, что сделать...

спустя 30 минут [обр] teho[досье]
2 первых ошибки решились добавлением <%@page import="javax.naming.*" %>
спустя 19 минут [обр] GRAy(14/259)[досье]
Ну а третья я думаю решится добавлением <%@page import="javax.sql.*" %> :)
спустя 3 часа 5 минут [обр] 30-ый(59/584)[досье]
На самом деле я бы очень советовал начинать тестирование на сервлетах. JSP это просто коллекция нелепых сообщений об ошибках.
спустя 12 минут [обр] teho[досье]

Ууу, все получилось! Ура! :-D Заработало. Всем спасибо!

Единственное, только... Субъективно, мое веб-приложение стало работать медленней как-то.

спустя 6 минут [обр] teho[досье]
И ещё в логах сервера вот этот момент интересует:
INFO: The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: здесь даются различные пути...
Версия Tomcat/5.5.17
спустя 6 минут [обр] teho[досье]
J2SE 1.4.2
Powered by POEM™ Engine Copyright © 2002-2005