Руководство по JDBC v.1
Предыдущий | Содержание | Следующий
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, и DCE).
Стандартный синтаксис JDBC URL показан ниже. Он имеет три части, разделенных двоеточием:
jdbc:<subprotocol>:<subname>JDBC URL состоит из:
jdbc
- протокола. Протокол, используемый в JDBC URL - всегдаjdbc
.<subprotocol> (подпротокола)
- это имя драйвера или имя механизма соединения с БД. Подпротокол может поддерживаться одним или несколькими драйверами. Лежащий на поверхности пример подпротокола - это "odbc", отведенный для URL, обозначающих имя источника данных ODBC. Например, для доступа к БД через мост JDBC-ODBC нужно использовать URL такого вида:jdbc:odbc:fred
В этом примере подпротокол задан как "odbc", а подимя "fred" является локальным источником данных.Если кому-то захочется использовать сервис имен (т.е. имя БД в JDBC-URL не будет действительным именем БД), то подпротоколом может быть сервис имен:
jdbc:dcenaming:accounts-payable
В этом примере URL указывает локальный сервис имен DCE, который должен разрешить имя БД "accounts-payable" в более определенное имя, которое далее будет использоваться для подключения к БД.<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-подпротоколов. Чтобы зарегистрировать подпротокол, надо послать письмо по адресу:
[email protected]
2.1.6 Выполняем SQL-запросы
После того как установлено соединение, оно используется для выполнения SQL-запросов к БД. JDBC не ограничивает синтаксис SQL-запросов, предоставляя, таким образом, большую гибкость в использовании специфичных для СУБД запросов или даже вообще не-SQL запросов. Правда, пользователь должен быть уверен, что СУБД "поймет" отсылаемые ей SQL-выражения и обрабатывать последствия такого "непонимания". Например, прилоежние, пытающееся вызвать хранимую процедуру в СУБД без поддержки хранимых процедур, сгенерирует исключение. Все драйверы, помеченные как JDBC COMPLIANTTM, реализуют возможности по крайней мере вводного уровня ANSI SQL-2 (entry level). Это означает, что пользователи могут положиться как минимум на этот стандартный уровень функциональности.В JDBC есть три класса для посылки SQL-запросов в БД и три метода в
интерфейсе Connection
создают экземпляры этих классов. Эти классы и
методы, которые их создают, перечислены ниже:
Statement
- создается методомcreateStatement
. ОбъектStatement
используется при простых SQL-запросах.PreparedStatement
- создается методомprepareStatement
. ОбъектPreparedStatement
используется в SQL-запросах с одним или более входными параметрами (IN parameters).PreparedStatement
содержит группу методов, устанавливающих значения входных параметров, которые отсылаются в БД при выполнении запроса. Экземпляры классаPreparedStatement
расширяют (наследуются от)Statement
и, таким образом, включают методыStatement
. ОбъектPreparedStatement
потенциально может быть более эффективным, чемStatement
, так как он прекомпилируется и сохраняется для будущего использования.CallableStatement
- создается методомprepareCall
. ОбъектыCallableStatement
используются для выполнения т.н. хранимых процедур - именованных групп SQL-запросов, наподобие вызова подпрограммы. ОбъектCallableStatement
наследует методы обработки входных (IN) параметров изPreparedStatement
, а также добавляет методы для обработки выходных (OUT) и входных-выходных (INOUT) параметров.
Connection
лучше использовать для
создания различных SQL-запросов:
Метод createStatement
используется для
- простых SQL-выражений (без параметров)
Метод prepareStatement
используется для
- SQL-выражений с одним или более входным (IN-) параметром
- простых SQL-выражений, которые исполняются часто
Метод 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
, что
повлечет за собой фиксацию изменений.
Предыдущий | Содержание | Следующий