HEAD>
Содержание | Предыдущий | следующий Руководство по JDBCTM для начинающих


2 Соединение

2.1 Обзор

Объект Connection представляет собой соединение с БД. Сессия соединения включает в себя выполняемые SQL-запросы и возвращаемые через соединение результаты. Приложение может открыть одно или более соединений с одной или несколькими БД.

2.1.1 Открытие соединения

Стандартный способ получения соединения - это вызов метода DriverManager.getConnection. Этому методу передается строка, содержащая т.н. "URL". Класс DriverManager, представляющий собой уровень управления в JDBC, пытается найти драйвер, который может соединиться к БД с помощью данного URL. Класс DriverManager содержит список зарегистрированных классов Driver, и при вызове метода getConnection он проверяет каждый драйвер и ищет среди них тот, который "умеет" соединятся с БД, указанной в URL. Метод connect драйвера использует этот URL для установления соединения.

Пользователь может пропустить этот управляющий уровень JDBC и вызывать непосредственно методы класса Driver для открытия соединения. Это может быть нужным в тех редких случаях, когда два или более драйвера могут обслужить заданный URL, но пользователь хочет выбрать конкретный из них. Тем не менее, намного проще возложить эту работу на класс DriverManager.

Следующий код демонстрирует открытие соединенияс БД, находящейся по URL "jdbc:odbc:wombat", с именем пользователя "oboy" и паролем "12Java":

    String url = "jdbc:odbc:wombat";
    Connection con = DriverManager.getConnection(url, "oboy", "12Java");

2.1.2 "URL" в обычном использовании этого термина

Чтобы не запутать читателя, мы сначала вкратце объясним термин "URL" в общем случае, а затем перейдем к обсуждению JDBC-URL.

URL (Uniform Resource Locator) представляет собой информацию для адресации ресурса в Интернет. Другими словами, это адрес ресурса.

Первая часть URL задает протокол, используемый для доступа к информации, и всегда заканчивается знаком ":". Среди протоколов наиболее популярны "ftp" ("file transfer protocol" - протокол передачи файлов), и "http" ("hypertext transfer protocol" - протокол передачи гипертекста). Протокол "file" означает, что ресурс находится в локальной файловой системе, а не в Интернет. Примеры URL:

    ftp://javasoft.com/docs/JDK-1_apidocs.zip
    http://java.sun.com/products/JDK/CurrentRelease
    file:/home/haroldw/docs/tutorial.html
Остальная часть URL, - то, что после первого двоеточия, - это то место, где находится источник данных. В случае протокола "file" оставшаяся часть URL - это путь к файлу. Для протоколов ftp и http оставшаяся часть URL идентифицирует хост (имя сервера) и необязательный путь к конкретном сайту или файлу. Например, ниже приведен URL домашней страницы фирмы JavaSoft. Этот URL указывает только имя хоста:

     http://www.javasoft.com

2.1.3     JDBC-URL

JDBC-URL предоставляет способ указания БД и определенного драйвера, который устанавливает соединение с данной БД. Разработчики драйверов определяют, что из себя представляет URL для доступа к БД с помощью конкретного драйвера. Пользователи же используют способ записи JDBC URL, указанный для конкретного драйвера. JDBC может только рекомендовать разработчикам JDBC-драйверов некоторые соглашения о формате JDBC-URL.

Так как JDBC-URL используются с различными драйверами, то они должны неизбежно быть очень гибкими. Во-первых, они допускают использование различными драйверами различных схем именования баз данных. Например, подпротокол odbc позволяет использовать значения атрибутов в URL.

Во-вторых, JDBC-URL дают возможность разработчикам jdbc-драйверов кодировать всю нужную для соединения информацию в URL.

В-третьих, с помощью JDBC-URL принципиально возможно осуществить "перенаправление": JDBC-URL может ссылаться на логический хост или имя БД, которое динамически транслируется в настоящее имя с помощью сетевой службы имен. Таким образом можно избежать непосредственного назначения хоста в JDBC URL. Существует несколько сетевых сервисов имен (DNS, NIS, and DCE).

Стандартный синтаксис JDBC URL показан ниже. Он имеет три части, разделенных двоеточием:

       jdbc:<subprotocol>:<subname>
JDBC URL состоит из:

  1. jdbc - протокола. Протокол, используемый в JDBC URL - всегда jdbc.
  2. <subprotocol> (подпротокола) - это имя драйвера или имя механизма соединения с БД. Подпротокол может поддерживаться одним или несколькими драйверами. Лежащий на поверхности пример подпротокола - это "odbc", отведенный для URL, обозначающих имя источника данных ODBC. Например, для доступа к БД через мост JDBC-ODBC нужно использовать URL такого вида:
          jdbc:odbc:fred
    
    В этом примере подпротокол задан как "odbc", а подимя "fred" является локальным источником данных.

    Если кому-то захочется использовать сервис имен (т.е. имя БД в JDBC-URL не будет действительным именем БД), то подпротоколом может быть сервис имен:

          jdbc:dcenaming:accounts-payable
    
    В этом примере URL указывает локальный сервис имен DCE, который должен разрешить имя БД "accounts-payable" в более определенное имя, которое далее будет использоваться для подключения к БД.

  3. <subname> (подимени) - это идентификатор БД. Значение подимени может менятся в зависимости от подпротокола, и может также иметь подподимя с синтаксисом, определяемым разработчиком драйвера. Назначение подимени - это предоставление всей информации, необходимой для поиска БД. В предыдущем примере достаточно строки "fred", так как оставшуюся часть информации предоставляет ODBC. Однако удаленная БД требует дополнительную информацию. Например, если БД находится в Интернет, то в состав подимени JDBC-URL должен быть включен сетевой адрес, подчиняющийся следующим соглашениям:
               //hostname:port/subsubname
Предполагая, что "dbnet" - это протокол соединения к хосту в Интернет, JDBC-URL может выглядеть так:

               jdbc:dbnet://wombat:356/fred

2.1.4     Подпротокол "odbc"

Подпротокол odbc зарезервирован для URL, которые определяют имена источников данных (DSN) ODBC и имеют специальную возможность задавать некоторое количество значений атрибутов после подимени (имени источника данных, DSN). Полный синтаксис подпротокола ODBC - следующий:

       jdbc:odbc:<data-source-name>[;<attribute-name>=<attribute-value>]*

Примеры корректных JDBC-URL для подпротокола odbc приведены ниже:

  jdbc:odbc:qeor7
  jdbc:odbc:wombat
  jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER
  jdbc:odbc:qeora;UID=kgh;PWD=fooey

2.1.5 Регистрация подпротоколов

Разработчик драйвера может зарезервировать имя подпротокола в JDBC-URL. Когда класс DriverManager "показывает" это имя своему списку зарегистрированных драйверов, и тот драйвер, который отвечает за этот подпротокол, должен "откликнуться" и установит соединение с БД. Например, odbc зарезервирован за рассмотренным выше мостом JDBC-ODBC. Кто-нибудь другой, например, Miracle Corporation, может зарегистрировать в качестве подпротокола "miracle" для jdbc-драйвера, который соединяется с СУБД Miracle. При этом никто другой уже не сможет использовать это имя.

Организация JavaSoft служит в качестве информационного реестра имен JDBC-подпротоколов. Чтобы зарегистрировать подпротокол, надо послать письмо по адресу:

      jdbc@wombat.eng.sun.com

2.1.6 Выполняем SQL-запросы

После того как установлено соединение, оно используется для выполнения SQL-запросов к БД. JDBC не ограничивает синтаксис SQL-запросов, предоставляя, таким образом, большую гибкость в использовании специфичных для СУБД запросов или даже вообще не-SQL запросов. Правда, пользователь должен быть уверен, что СУБД "поймет" отсылаемые ей SQL-выражения и обрабатывать последствия такого "непонимания". Например, прилоежние, пытающееся вызвать хранимую процедуру в СУБД без поддержки хранимых процедур, сгенерирует исключение. Все драйверы, помеченные как JDBC COMPLIANTTM, реализуют возможности по крайней мере вводного уровня ANSI SQL-2 (entry level). Это означает, что пользователи могут положиться как минимум на этот стандартный уровень функциональности.

В JDBC есть три класса для посылки SQL-запросов в БД и три метода в интерфейсе Connection создают экземпляры этих классов. Эти классы и методы, которые их создают, перечислены ниже:

  1. Statement - создается методом createStatement. Объект Statement используется при простых SQL-запросах.
  2. PreparedStatement - создается методом prepareStatement. Объект PreparedStatement используется в SQL-запросах с одним или более входными параметрами (IN parameters). PreparedStatement содержит группу методов, устанавливающих значения входных параметров, которые отсылаются в БД при выполнении запроса. Экземпляры класса PreparedStatement расширяют (наследуются от) Statement и, таким образом, включают методы Statement. Объект PreparedStatement потенциально может быть более эффективным, чем Statement, так как он прекомпилируется и сохраняется для будущего использования.
  3. CallableStatement - создается методом prepareCall. Объекты CallableStatement используются для выполнения т.н. хранимых процедур - именованных групп SQL-запросов, наподобие вызова подпрограммы. Объект CallableStatement наследует методы обработки входных (IN) параметров из PreparedStatement, а также добавляет методы для обработки выходных (OUT) и входных-выходных (INOUT) параметров.
Нижеследующий список дает представление о том, какой именно из методов объекта Connection лучше использовать для создания различных SQL-запросов:

Метод createStatement используется для

Метод prepareStatement используется для

Метод prepareCall используется для

2.1.7 Транзакции

Транзакция состоит из одного или более выражений, которые поле выполнения либо все фиксируются (commit), либо все откатываются назад (rollback). При вызове метода commit или rollback текущая транзацкия заканчивается и начинается другая.

Каждое новое соединение по умолчанию находится в режиме автофиксации (auto-commit), что означает автоматическую фиксацию (commit) транзакции после каждого запроса. В этом случае транзакция состоит из одного запроса. Если auto-commit запрещен, транзакция не заканчивается вплоть до явного вызова commit или rollback, включая, таким образом, все выражения, выполненные с момента последнего вызова commit или rollback. В этом случае все SQL-запросы в транзакции фиксируются или откатываются группой.

Метод фиксации commit делает окончательными все изменения в БД, проделанные SQL-выражением, и снимает также все блокировки, установленные транзакцией. Метод rollback проигнорирует, "отбракует" эти изменения.

Иногда пользователю нужно, чтобы какое-либо изменение не вступило в силу до тех пор, пока не вступит в силу предыдущее изменение. Этого можно достичь запрещением auto-commit и группировкой обоих запросов в одну транзакцию. Если оба изменения произошли успешно, то вызывается метод commit, который переносит эффект от этих изменений в БД; если одно или оба запроса не прошли, то вызывается метод rollback, который возвращает прежнее состояние БД.

Большинство JDBC-драйверов поддерживают транзакции. На самом деле драйвер, соответствующий спецификации JDBC, обязан поддерживать их. Интерфейс DatabaseMetaData предоставляет информацию об уровнях изолированности транзакций, которые поддерживаются данной СУБД.

2.1.8 Уровни изолированности транзакций

Есть несколько способов разрешения конфликтов между одновременно выполняющимися транзакциями. Пользователь может задать уровень изолированности, то есть уровень внимания, которое СУБД должна уделить при разрешении возможных конфликтов. Например, что будет, если одна транзакция изменит какое-либо значение, а вторая транзакция прочитает его перед тем как первая выполнит commit или rollback? Допустимо ли это, например, если это значение, будучи уже прочитанным второй транзакцией, окажется некорректным и будет откатано (rolled back) первой? Пользователь JDBC может указать СУБД на возможность чтения измененных значений до того, как выполнится commit ("грязное чтение", "dirty reads"). Это делается так (con - это соединение с БД):

    con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
Чем выше уровень изолированности транзакций, тем больше внимания СУБД уделяет устранению конфликтов. Интерфейс Connection определяет пять таких уровней. Минимальный из них соответствует случаю, когда транзакции не поддерживаются вовсе, а максимальный - невозможности существования более одной транзакции в любой момент времени. Обычно, чем выше уровень изолированности, тем медленнее выполняется приложение (из-за избыточной блокировки и уменьшенной конкурентности пользователей). При выборе конкретного уровня изолированности разработчик должен найти золотую середину между потребностями в производительности и требованиями к целостности данных. Очевидно, что реально поддерживаемые уровни зависят от возможностей используемой СУБД.

При создании объекта Connection его уровень изолированности зависит от драйвера или БД. Пользователь может вызвать метод setIsolationLevel, чтобы изменить уровень изолированности транзакций, и новое значение уровня будет установлено до конца сессии. Чтобы установить уровень изолированности только для одной транзакции, надо установить его перед выполнением транзакции и восстановить прежнее значение после ее завершения. Изменение уровня изолированности во время самой транзакции нежелательно, так как произойдет автоматический вызов commit, что повлечет за собой фиксацию изменений.


Содержание | Предыдущий | Следующий
Главная страница