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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> JDBC как? 
:(
    Опции темы
Гость_junior
Дата 28.4.2005, 14:50 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Я еще новичок, и поэтому задаю этот вопрос.
Скажите, как получить доступ из приложения к базе на Оракле 9i. Какой драйвер и как использовать?
  Вверх
batigoal
Дата 28.4.2005, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



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


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


Unregistered











Если не сложно, то да! а то я никак не могу разобраться.
  Вверх
batigoal
Дата 28.4.2005, 21:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Ну, если без деталей, то так (драйвер можно качнуть на сайте Оракла):

Код

Connection conn;
Statement stmt;
PreparedStatement pstmt;
ResultSet rs;

URL = new String("jdbc:oracle:thin:@localhost:1521:db");
user = new String("15011");
password = new String("15011");
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conn=DriverManager.getConnection(URL,user,password);
stmt=conn.createStatement();


Сейчас просто времени нет расписывать, извини smile
Загляни в документацию JDBC.


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


Опытный
**


Профиль
Группа: Участник
Сообщений: 327
Регистрация: 30.10.2004

Репутация: 1
Всего: 21



Вот "выдержки" из рабочей программы
Код

import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
...
public class MyOracle
  {
    public  Connection   conn;
    public  String       url= "jdbc:oracle:thin:@localhost:1521:bank2";
    public  String       userName= "probe";
    public  String       userPwd= "probe";
...
    public MyOracle()
      {
        try
          {
            DriverManager.registerDriver(new OracleDriver());
          }
          catch(Exception e)
            {
              e.printStackTrace();
            }
      }
...
    private Connection setConnection() throws SQLException
      {
        conn = (OracleConnection)DriverManager.getConnection(url, userName, userPwd);
        return conn;
      }

    public Connection getConnection() throws SQLException
      {
        if (conn == null)
          {
            setConnection();   
          }
        return conn;
      }

    public void closeConnection() 
      {
        if (conn != null)
          {
            try
            {
              conn.commit();   
              conn.close();   
            }
            catch (SQLException e)
              {
                e.printStackTrace();
              }
          }
      }
Если будут вопросы и по conn - задавай




--------------------
Хотите поговорить об этом?
PM   Вверх
Се ля ви
Дата 2.5.2005, 20:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



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

public class ClassName {

    private Statement stmt;
    private ResultSet rs;

    public ClassName(){
        try {
            Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); // Загрузка драйвера

            stmt = DriverManager
                        .getConnection(                                       // Подключение к Базе Данных:
                            "jdbc:oracle:thin:@domain:1521:sid", // строка запроса
                            "user",                                                 // пользователь
                            "pass"                                                 // пароль
                        )
                            .createStatement();

        } catch (SQLException e){ e.printStackTrace(); }
    }
    public int method(){
        try {
             rs =
                stmt
                    .executeQuery(
                        "select field1 " +
                        "from table1"
                    );

            if (rs.next()) return Integer.parseInt(rs.getString(1));
            else return 0;


        } catch (SQLException e) { e.printStackTrace(); );
        return 0;
    }

    public void finalize(){

        try {
            stmt.close();
            stmt.getConnection().close();

        } catch (SQLException e){ e.printStackTrace(); }
    }
}


Это сообщение отредактировал(а) Се ля ви - 4.5.2005, 00:02


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

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


Unregistered











Спасибо, но все равно не понятно.
Во-первых, где можно взять документацию по jdbc понятную?

Во-вторых, что за пакеты:
Код

oracle.jdbc.OracleConnection,
oracle.jdbc.OracleDriver?


В-третьих, тут используется мост JDBC-ODBC:
Код

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver")?


И последнее, у меня Oracle9iAS стоит, я так понимаю там есть сам JDBC драйвер. Что мне с ним вообще делать? Куда копировать? Как вообще все это происходит. Расскажите, пожалуйста, по-подробнее. Или ссылочку киньте8)

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


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


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

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



Гость_junior
зарегистрируйся, пожалуйста smile

Цитата
где можно взять документацию по jdbc понятную?

На сайте SUN`а, например - http://java.sun.com/products/jdbc/index.jsp. В книжке ещё можно, в т.ч. и в электронной. Вообще, JDBC - это часть J2EE, соответственно поройся в ссылках на описание технологий J2EE.


Цитата
Во-вторых, что за пакеты:

Очевидно, драйверы.

Цитата
тут используется мост JDBC-ODBC

угу


Цитата
И последнее, у меня Oracle9iAS стоит, я так понимаю там есть сам JDBC драйвер. Что мне с ним вообще делать? Куда копировать? Как вообще все это происходит. Расскажите, пожалуйста, по-подробнее.

Копируй его в то место, где он будет доступен для твоей JRE - вот и всё. Например, в директорию \jre\lib\ext
После этого перегружай сервер или что там у тебя Java использует - и вперёд, с песней smile


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

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


Leprechaun Software Developer
****


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

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



Цитата
Во-вторых, что за пакеты:

Это Oralce-овская реализация классов java.sql.Connection java.sql.Driver. Кстати Oralce поставляет 2 типа драйверов thin и oci. В примерах что были используется thin. Для своей работы он требует только jar с драйверами. oci драйвер требует установленного клиента и использует информацию из tsnames.ora, и чуток побыстрее (при массовом insert он у меня оказался быстрее на 5%).


--------------------
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   Вверх
Stampede
Дата 3.5.2005, 22:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


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

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



Цитата
Я люблю делать всё короче


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

Цитата
драйвер оставляю возможность передавать параметром по этому импортировать внутри кода


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


Цитата
Connection использую неявно


Тоже ничего хорошего. Что мы видим? Переменная типа Connection объявлена как приватная и типа инкапсулирована, и мы ее не видим и не слышим и знать про нее не хотим, а рассматриваем класс как объект, который знает, как получить какие-то определенные данные. Мысль понятная, но не все на самом деле так просто.

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

Для этого нужно, чтобы или коннекция была доступна извне, или чтобы класс позволял в явном виде выполнять:
  • открытие;
  • фиксацию;
  • откат;
  • закрытие;

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

Резюмируя, что мы имеем? Мы имеем класс, где в одну кучу навалены вещи, которые при хорошем дизайне должны быть четко разделены:

- Выделение коннекций

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

- Выполнение действий по доступу к данным

Сама по себе идея неплохая - сгруппировать различные SQL команда в одном классе, но это годится только для небольших приложений, где количество различных запросов находится в обозримых пределах. Даже если идти по такому пути, нужно не забывать еще несколько вещей: по возможности использовать PreparedStatement вместо Statement, использовать внешниюю коннекцию, не ловить исключения.

- Управление жЫзненым циклом коннекций

Ну про метод finally() я вообще молчу. Очевидно, имелось в виду автоматическое закрытие коннекции при уничтожении объекта. Для этого служит метод finalize(), но использовать его для управления жизненным циклом таких нежных ресурсов как датабазные коннекции - идея не очень хорошая. Почему - могу объяснить. Потом.

Общий вывод: не используйте этот пример как руководство к действию

Се ля ви, чур, без обид - сам напросился smile
PM WWW   Вверх
Гость_junior
Дата 3.5.2005, 23:34 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Ок, огромное спасибо. Пойду разбираться в столь исчерпывающей информации. Спасибо всем, если появятся вопросы, то обязательно задам.
А у меня тут первая проблемка, копирую архив с классами от Оракла в указанную директорию
Цитата
\jre\lib\ext

компилятор грит, что КлассНотФоунд. Копирую в директорию, указанную в переменной Класспатх - то же самое. А вот копирую в ту же директорию где и программка, то все ок. Почему так?
Спасибо
  Вверх
Се ля ви
Дата 4.5.2005, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(Stampede @ 3.5.2005, 22:24)
Цитата (Се ля ви @ 2.5.2005, 20:14)
драйвер оставляю возможность передавать параметром по этому импортировать внутри кода

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

Дык я тут каак раз и привёл код для замены. Просто строку запроса к драйверу меняем на параметр, читаемый из конфига - и загружается нужный драйвер smile Просто хотел продемонстрировать как можно имея строку с именем класса, загрузить драйвер уже в скомпилированном коде smile

Насчёт остального - не вижу особенного криминала в том, что я не сохраняю специально ссылку на объект connection - как раз наоборот, ИМХО, в больших программах от большого количества перемменных можно запутаться, а сам объект connection, соответствующий данному statement`у легко получить, вызвав его метод stmt.getConnection(), что я и проделывал в конце кода, когда коннекшн нужно закрыть. Т.е. от того, что я не сохранил ссылку, объект я никуда не потерял и если нужен, могу ссылку на него легко получить. smile

Впрочем это всё ИМХО. Так легче персонально мне, и я вовсе не пытаюсь тут кому-то чего-то навязывать. Каждый делает как проще именно ему. Я вот не люблю огромного количества переменных, по-этому люблю их использовать неявно и вытаскивать когда нужно. Я могу понять, если кому-то это удобней, чем помнить, как что когда откуда вытаскивать.

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

Имено по-этому в конце - stmt.getConnection().close(); smile

Цитата(Stampede @ 3.5.2005, 22:24)
не ловить исключения.

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

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

Да, совсэм забыл, ща поправлю...

Stampede вообще, многовато требований к типовому примеру у тебя, не находишь? Ну да, вместо finalize() можно использовать шаблон Singleton, или другие иинтересности, но это уже не для начинающих будет уж точно, а человеку бы в этом разобраться суметь - и то ладно... Это потом уж можно дальше копать, если интерес не отпадёт!..

P.S. Хотя действительно, соглашусь, что начинающим такой пример лучше не использовать - человек должен сам придти к такой простоте кода, иначе не будет
а) её ценить
б) понимать по-другому организованный код других программистов.

P.P.S.
Цитата(Stampede @ 3.5.2005, 22:24)
Се ля ви, чур, без обид - сам напросился

Да ладно, коли по делу, так не жалко... smile Лишь бы человек правильно сориентировался. smile
Добавлено @ 00:11
Цитата
А у меня тут первая проблемка, копирую архив с классами от Оракла в указанную директорию
Цитата
\jre\lib\ext

компилятор грит, что КлассНотФоунд

Попробуй винду перезагрузить, может JRE старая не закрылась?.. Должен работать вариант с \jre\lib\ext - проверено неоднократно.
Цитата
копирую в ту же директорию где и программка, то все ок.

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

А у тебя не может несколько JRE стоять?.. Тогда ты, может быть, не в ту суёшь? Например, в средах разработки типа JBuilder`а, IDEA и Eclipse - свои собственные JRE.

Можешь, конечно, использовать драйвер как библиотеку, но это не даст тебе его именно конфигурить, например из сервера...

Это сообщение отредактировал(а) Се ля ви - 4.5.2005, 00:35


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

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


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


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

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



Цитата(Stampede @ 3.5.2005, 22:24)
Почему - могу объяснить. Потом.

Объясни сейчас, плз smile
Цитата(Stampede @ 3.5.2005, 22:24)
коннекция

Умоляю... соединение! smile


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


Unregistered











Цитата
А у тебя не может несколько JRE стоять?.. Тогда ты, может быть, не в ту суёшь? Например, в средах разработки типа JBuilder`а, IDEA и Eclipse - свои собственные JRE.

у меня стоит NetBeans IDE 3.6 и jre там своего нету...по-моему. стоит так же j2sdk1.4.2_04 в jre директорию которого я и кидал классы Оракла. Так значит на переменную Classpath никакой завязки нет?
спасибо
  Вверх
batigoal
Дата 4.5.2005, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата
значит на переменную Classpath никакой завязки нет?

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


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
Се ля ви
Дата 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   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

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

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


 




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


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

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