Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:JAVA. Серверные приложения
.pdf
Часть 5. Работа с базами данных при помощи Java 281
бизнес-правила, применяемые к бизнес-объектам, и не всегда эти бизнес-объекты имеют базовый тип, используемый в СУБД. В таблице
39.2.1 перечислены основные SQL-типы, их представления в СУБД DB2
и Java примитивы отражающие основные типы данных.
Таблица 39.2.1
Òèï Java òèï SQL DB2
boolean BIT SMALLINT
byte TINYINT SMALLINT
char CHAR(1) CHAR(1)
double DOUBLE FLOAT
float REAL REAL
int INTEGER INTEGER
long BIGINT BIGINT
short SMALLINT SMALLINT
String VARCHAR VARCHAR(2000)
java.math.BigDecimal NUMERIC DECIMAL
byte[] VARBINARY BLOB
java.sql.Date DATE DATE
java.sql.Time TIME TIME
java.sql.Timestamp TIMESTAMP TIMESTAMP
java.util.Date TIMESTAMP TIMESTAMP
java.io.Serializable VARBINARY BLOB
И все-таки иногда, а в последнее время все чаще, всех поддерживае-
мых типов не хватает для работы приложений, и для этой ситуации
предусмотрена возможность создания пользовательских типов данных
user-defined types (UDTs).
Комбинация совместного использования UDT и LOB дает в руки раз-
работчика существенные преимущества при работе с данными. LOB позволяет избежать трудоемкой работы по разделению данных на составные части и раскладыванию этих частей по разным столбцам. Использование UDT позволяет создавать комбинированные типы данных и
решает проблему отсутствия необходимых Web-приложению типов.
В добавление к вышесказанному можно добавить еще несколько преимуществ использования UDT.
Поддержка объектно-ориентированного программирования DB2 по-
зволяет группировать родственные объекты в связанные типы данных.
Эти типы имеют название (имя), внутреннее представление и определенное поведение. Используя UDT, можно сообщить DB2 название
(имя) нового типа и как это представлено внутренне. LOB — одно из
возможных внутренних представлений для нового типа и наиболее подходящее представление для больших, сложных структур данных.

282 Часть 5. Работа с базами данных при помощи Java
В объектно-реляционной системе важно не только отслеживать со-
стояние сохраняемых объектов, но и их поведение. Таким образом, поведение данных представляет собой ресурс, который может совместно
использоваться несколькими приложениями.
Строгая типизация объектов, используемая в DB2, гарантирует, что
определенные типы могут работать только со своим функциями. В DB2
поведение для определенных типов можно описать при помощи пользовательских функций.
Такая банальная вещь, как складывание двух чисел, может вызвать
большой скандал, если эти числа представляют различные мировые валюты и производится обычная выборка по стоимости. Разницу между
японской йеной и американским долларом объяснять не нужно, но типов данных, отражающих денежный эквивалент в современной версии
DB2, не существует, да они и не нужны. В других СУБД величины
представлены особым типом MONEY. Для решения этой задачи можно
воспользоваться возможностью, предоставляемой СУБД, по использованию пользовательских типов.
Предоставляя пользователям возможности определять собственные
типы данных, а также возможности определять правила, управляющие
поведением активных данных, имеется возможность повысить ценность
хранимых данных за счет расширения их семантического содержания.
Тенденция расширения семантического сокращения хранимых данных,
проще говоря, использование UDT, является на сегодняшний день наиболее важным направлением развития в области управления базами
данных.
UDT — это механизм для моделирования и хранения сложных типов
данных в СУБД. У UDT может быть несколько полей, например, для
геометрического объекта — это список координат точек. Поэтому в различных системах управления базами данных DB2 не исключение,
встроена поддержка создания пользовательских типов данных, именуемых как особый тип (distinict type). Каждый из особых типов порожден
от одного из базовых типов, но имеет собственный набор допустимых
операций. После создания особого типа единственными операторами
применяемые к данным этих типов являются операции сравнения с
данными того же типа. Очень просто указать операции, используемые
при работе с особыми типами. Стандарт SQL позволяет переопределять
функции для разрешения применения оператора к особому типу. Необходимо просто создать новую функцию, назвать ее так же, как сам оператор, описать тело и указать в виде входящих и выходящих параметров значения особого типа.
В DB2 расширена поддержка UDT — это позволяет создавать табли-
цы только из UDT. Кроме того, теперь в одном объекте UDT можно использовать и другие типы UDT. Это значит, что атрибуты UDT больше
не ограничиваются базовыми типами SQL. Например, в DB2 описаны
функции преобразования, трансформирующие сложную структуру описанных в пользовательском приложении в стандартные базовые типы
SQL. Эти функции обеспечивают и обратное преобразование базовых
типов SQL в UDT. Эти преобразования нужны для перемещения UDT в
базу данных и обратно.

Часть 5. Работа с базами данных при помощи Java 283
UDT подобен другим объектам базы данных, такие, как таблицы, ин-
дексы, создаются оператором CREATE. Используя CREATE DISTINCT
TYPE, оператор определяет новый тип UDT.
UDT основаны на встроенных типах. При создании UDT необходимо
определить родовой тип, от которого порожден пользовательский и операторы, работающие с данным типом. DB2 не позволяет использовать
созданные пользовательские типы для порождения других типов.
Для создания пользовательского типа используется оператор DB2
CREATE DISTINCT TYPE.
Пользовательский тип деньги определен от предназначенного для
различных обработок денежных единиц. Основное здесь — наличие
двух цифр после запятой. Для разных значений необходима возможность сравнения. Ниже созданы пользовательские типы отражения различных денежных единиц.
CREATE DISTINCT TYPE us_dollar AS DECIMAL (9, 2) WITH
COMPARISONS
CREATE DISTINCT TYPE euro AS DECIMAL (9, 2) WITH COMPARISONS
CREATE DICTINICT TYPE polygon AS BLOB(1M)
Фраза WITH COMPARISONS указывает, что два значения в долла-
рах могут сравниваться между собой, так же как два значения в йенах,
но значения доллара не могут сравниваться со значениями йены, хотя
оба типа имеют базовым один тип — DECIMAL. Кроме того, ни одно из
этих значений нельзя сравнивать с любым объектом, также представляющим базовый тип DECIMAL.
Еще один пример иллюстрирует пользовательский тип, описываю-
щий работу и имеющий тип CLOB с размером в 32 кбайт.
CREATE DISTINCT TYPE personal.application_form AS CLOB(32K)
При создании UDT СУБД DB2 генерирует функцию преобразования
созданного типа к базовому и обратно. После создания UDT единственными, которыми можно пользоваться при работе с созданным UDT, являются стандартные операторы сравнения с данным того же типа. Для
расширения возможностей использования типов необходимо явно указать операции управления созданными пользовательскими типами.
Можно просто указать, какие из операторов базового типа имеют смысл
при применении к определенным созданным типам. Каждый из операторов, таких, как сложение (+), реализован в виде функции, имеющей
то же имя, что и оператор. Чтобы разрешить использование данного
оператора к созданному типу данных, необходимо просто создать новую
функцию, которая имеет то же имя, что и оператор, но возвращаемым
значением является UDT как входящий, также являющийся созданным
UDT.
CREATE FUNCTION «+» (DOLLARS, DOLLARS) RETURNS DOLLARS
SOURCE SYSIBM. «+» (DECIMAL(), DECIMAL());
CREATE FUNCTION «*» (INTEGER, DOLLARS) RETURNS DOLLARS
SOURCE SYSIBM. «*» (INTEGER(), DECIMAL());

284 Часть 5. Работа с базами данных при помощи Java
В качестве реализации функции-оператора можно указать как ис-
точник реализации SOURCE SYSIBM. «+» (DECIMAL(), DECIMAL());
предоставляемая СУБД для базового типа, т. е. операция с UDT, будет
производиться так же, как она производится для базового типа. В вышеуказанном примере создаются две функции. Первая предназначена
для сложения двух значений DOLLARS, а во второй функции определяется операция умножения для значений DOLLARS. Здесь необходимо
учесть один маленький нюанс. Умножение двух значений DOLLARS
может дать неправильный результат, поскольку оба представляют десятичное значение, в то время как использование пары INTEGER,
DECIMAL сохранит значение после десятичной точки при умножении.
Но описанная функция создалась именно для умножения различных
чисел со значением DOLLARS, и если пользователь попробует умножить два значения DOLLARS, то СУБД выдаст сообщение о возникшей
ошибке, так как функция по умножению значений DOLLARS не определена.
За счет использования реализации встроенных функций можно чет-
ко указать набор операторов, имеющих смысл для UDT. Конечно, иногда может потребоваться добавить особенные свойства к создаваемым
UDT, помимо операторов базового типа. Можно написать функцию на
Java и зарегистрировать в базе данных. DB2 содержит около 100 функций для выполнения самых различных операций с числами, строками,
датами и другими базовым типами. Но для описания поведения UDT
используются функции, определенные пользователем. В нашем конкретном случае для описания поведения UDT будет использоваться
язык программирования Java.
39.3. SQLJ и функции определенные пользователем (UDF)
В современных СУБД определены соглашения по передаче парамет-
ров определяемой пользователем функции (user defined function UDF) в
предоставляемую пользователем программу, реализующую данную
функцию. Пользовательские функции являются прекрасным подспорьем при создании приложений по обработке данных, которым не хватает
стандартных средств. UDF создаются на любом языке программирования — Visual Basic, C/C++ или Java. Приложения, реализованные на
языке программирования, содержат синтаксические конструкции базового языка, в которые включены любые SQL-операторы, возвращающие
простые скалярные значения или таблицы. Использование различных
языков программирования при создании UDF еще точно не стандартизировано, но для самых популярных языков, таких, как JavaиС++,
уже описаны определенные правила, конкретные для каждой версии
различных СУБД. Использование конкретного языка зависит от возможностей СУБД по поддержке данного языка.
Создание пользовательских функций User-Defined Functions (UDFs)
Создание пользовательской функции на Java состоит из нескольких
шагов, которые практически не отличаются от этапов создания обычно-

Часть 5. Работа с базами данных при помощи Java 285
го приложения. Любые Java клиентские приложения, написанные с использованием SQLJ или JDBC, могут вызывать UDF.
Написать UDF на используемом языке, например Java, содержа-
•
щем SQL-операторы
Компилировать UDF на соответствующем компиляторе. В случае
•
использования Java, это должен быть стандартный java-компилятор, входящий в пакет JDK. В пакете разработчика DB2 имеется
собственный java-комилятор.
После создания функцию необходимо зарегистрировать в базе дан-
•
ных. В DB2 существует специальный SQL-оператор, выполняющий
роль регистратора, — CREATE FUNCTION. Если предполагается
использование функции более чем в одной базе данных, оператор
CREATE FUNCTION выполняется для каждой зарегистрированной
базы данных. Оператор CREATE FUNCTION определяет типы параметров и тип возвращаемого значения. Одной из особенностей
UDF, используемых в DB2, является управление расположением
пользовательской функцией в системной области памяти DB2. Для
этого в DB2 имеются SQL-операторы FENCED или NOT FENCED.
Для более подробного ознакомления с возможностями данных операторов следует обратиться к руководству использования SQL в
документации на DB2. Очень важно защитить исполняемый файл,
реализующий функции, так как его исполнение производится при
вызове функции без последующей проверки системой.
•
Перед началом использования созданной функции желательно
протестировать работу, производимую UDF.
Особое внимание уделяется созданию пользовательских функцией,
поскольку большую часть работы можно выполнить в самой базе данных. Использование сторонних приложений в бизнес-логике приводит к
значительному увеличению обработки SQL-запросов. Скорость работы
Web-приложения значительно увеличивается при правильном проектировании компонентов. Компонент, ответственный за бизнес-логику, должен выполняться в базе данных, а не во внешних компонентах, какими
бы быстрыми компоненты ни были.
Комбинацию имени функции, тип ее параметров называют прототи-
пом функции. Что под этим подразумевается? Большинство современных языков программирования — и в данном случае SQL не исключение — имеют встроенную возможность перегружать функции, т. е., используя одно имя функции, передавать ей различные аргументы. При
вызове конкретной функции СУБД активизирует ту функцию, чьи аргументы наиболее точно соответствуют действительным типам аргументов.
Хранимые процедуры и функции определяют действия пользователя
при работе с базой данных. Вызов пользовательской функции осуществляется посредством стандартного SQL-оператора CALL. SQLJ не накладывает никаких ограничений по вызову функций созданных на другом языке. Так что оператор CALL можно использовать в SQLJ-приложении, без каких-либо доработок и вызывать любую функцию или
процедуру, реализованную даже не на Java.

286 Часть 5. Работа с базами данных при помощи Java
#sql { CALL MY_PROCEDURE(:arg) };
{intx; #sqlx={VALUES( F(name) ) }; }
Хранимые процедуры имеют три типа параметров: IN, OUT, INOUT.
Параметры типа IN передаются в хранимую процедуру и являются JAVA-переменными. Возвращаемые значения являются типами OUT и
INOUT и представляют собой массивы данных. О создании хранимых
процедур для каждой конкретной СУБД лучше посмотреть документацию, поставляемую производителем базы данных. В DB2 используется
оператор CREATE PROCEDURE, в котором содержатся имя процедуры,
аргументы, местоположение.
В DB2 реализована поддержка создания пользовательских функций
на языке Java. Пользовательские функции, используемые в DB2, созданные на языке Java, работают с любыми данными, определенные пользователем, могут использоваться в любом SQL-выражении.
Создание пользовательских функций с использованием Java допол-
няет SQLJ-приложение различными особенностями. Кроме LOB и UDT,
гибкость приложению можно задать, используя различные типы поведений для каждого объекта базы данных. Создание пользовательской
функции при помощи Java определяется следующим шагами:
Функция создается как Java-метод.
Затем производится стандартная операция компилирования в ра-
бочий байт-код, после ÷åãî используется SQL-оператор CREATE
FUNCTION.
При декларировании UDF аргументы передаются в SQL-запрос, ис-
пользуя Java-метод.
import COM.ibm.db2.app.*;
public class sample extends UDF {
public void test(String arg1, Blob arg2, String arg3, int result) {... } }
arg1, arg2, arg3, и result объекты Java-классов, совместимые с SQL-типами.
В UDF, реализованных с помощью Java, нельзя использовать стан-
дартные потоки ввода-вывода (System.in, System.out, and System.err).
В обычной ситуации обращение к базе данных посредством встроен-
ных функций используется достаточно часто. DB2 имеет ряд встроенных SQL-операторов, предназначенных для ускорения работы UDF.
Обязательным условием работы с пользовательской функцией явля-
ется регистрация функции в базе данных. В версии 6.1 DB2 в SQL-операторе CREATE FUNCTION используется специальный параметр
PARAMETER STYLE JAVA, указывающий, что функция создана на Java. DB2 имеет встроенную возможность работы с параллельным исполнением UDF. Параметр ALLOW PARALLEL, указанный при SQL-операторе CREATE FUNCTION, предназначен для распараллеливания выполнения нескольких функций.
После создания UDF классы, содержащие пользовательские функ-
ции, можно поместить в jar-архив для дальнейшего использования. jarархив можно прописать в файле свойств sqlj.properties, содержащий пару sqlj.install_jar= jar-архив. Для вызова созданной UDF можно воспользоваться командной строкой DB2, CALL SQLJ. INSTALL_JAR, где

Часть 5. Работа с базами данных при помощи Java 287
указан путь к jar-архиву и сам класс пользовательской функции. Удаление пользовательской функции из базы данных происходит по тем
же правилам:
CALL SQLJ.REMOVE_JAR('myProc_jar')
Java-клиентские приложения, написанные с использованием SQLJ
или JDBC, могут вызывать UDFs. Необходимо наличие в системе трех
компонентов для возможности использования пользовательских функций (UDF).
Входные параметры определяемой пользователем функции переда-
ются в клиентскую программу в месте с выходящими параметрами. После написания клиентской программы, содержащей UDF, ее необходимо
отранслировать, поместить в созданный байт-код, в случае с Java, исполняемый класс — в каталог, доступный серверу базы данных.
Большие объекты, пользовательские типы данных и пользователь-
ские функции каждое само по себе представляет мощное средство. Но
действительную мощность СУБД приобретает при совместном использовании этих средств.
Глава 40. Сравнение SQLJ и JDBC
Бизнес-логика Web-приложений основана на активном использова-
нии базы данных.
Стандартный набор API по работе с базами данных JDBC, прекрасно
подходит для работы с различными СУБД. Использование JDBC предназначено для создания динамических SQL-запросов, т. е. в тех случаях, когда выбор SQL-оператора зависит от программы, и реализованных на языке Java. JDBC использует не только различные драйверы
для доступа к различным СУБД, но и набор API для обслуживания
SQL-запросов.
Очень важной техникой, используемой в Web-приложениях, являет-
ся объединение связей (connection pooling), реализованная на Application Server. Когда логика приложения, используемая в клиентской сессии, нуждается в данных, размещенных в базе данных, в пуле остаются
значения предыдущих значений соединения. И если данный пользователь уже имел контакт с базой данных, то из пула выбираются значения его последнего успешного соединения.
SQLJ более широко использует упрощенный синтаксис по сравнению
с JDBC. SQLJ-транслятор генерирует статические SQL-запросы, .sqlj
использует для доступа встроенные объекты, в то время как в JDBCприложении инициализируются специальные классы.
JDBC API позволяет написать Java-программу с динамическими
SQL-вызовами. Обычно JDBC-программы выполняют SQL-операторы с
привилегиями пользователя, загрузившего программу. SQLJ-программы
выполняют SQL-операторы с привилегиями пользователя, создавшего
данный пакет.

288 Часть 5. Работа с базами данных при помощи Java
С выходом новой версии основного набора API Java, называемого в
народе Java 2 и появлением расширений J2EE уровня предприятий,
компания SUN анонсировала выход новой версии спецификации для
доступа к базам данных JDBC. Данная спецификация расширена и имеет ряд дополнительных возможностей по работе с СУБД.
Компания IBM поставляет только один пакет по расширению
SQLJ — COM.ibm.db2.sqlj, содержащий набор классов по локализации
SQLJ-сообщений.
Соответствие типов SQL типам Java приведено в таблице:
SQL Column Type Java Type (UDF) Java Type (Stored Procedure)
SMALLINT short short
INTEGER int int
BIGINT long long
FLOAT double double
REAL float float
DECIMAL java.math.BigDecimal java.math.BigDecimal
NUMERIC java.math.BigDecimal java.math.BigDecimal
CHAR(n) String String
CHAR(n) FOR BIT DATA Blob Blob
C null-terminated string String String
VARCHAR(n) String String
VARCHAR(n) FOR BIT Blob Blob
LONG VARCHAR String String
LONG VARCHAR FOR BIT DATA_ Blob Blob
GRAPHIC(n) String String
C null-terminated graphic string String String
VARGRAPHIC(n) String String
LONG VARGRAPHIC String String
BLOB(n)( Blob Blob
CLOB(n) Clob Clob
DBCLOB(n) Clob Clob
DATE String String
TIME String String
TIMESTAMP TIMESTAMP TIMESTAMP
Использование SQLJ имеет ряд преимуществ перед использованием
JDBC.
Во-первых, для каждого встроенного SQL-оператора в SQLJ-прило-
жении создается свой собственный скомпилированный оператор. Этот
оператор применяется исключительно в одной точке программы. В при-

Часть 5. Работа с базами данных при помощи Java 289
ложении, использующем JDBC, каждый SQL-оператор идентифицируется по имени. Имя оператора позволяет другим частям программы обращаться к данному оператору.
Во-вторых, SQLJ использует статические операторы, известные уже
на момент написания SQLJ-приложения, а вот если эти операторы неизвестны, то необходимо воспользоваться JDBC-технологией.
В-третьих, при организации соединения с базой данных JDBC рабо-
тает со значениями, передаваемыми в программу, SQLJ работает со
значениями по умолчанию. Это значит, что сама программа будет заботиться о верности данных, обеспечивающих соединение с рабочей базой
данных. Объект класса Connection Context содержит все параметры соединения.
В-четвертых, встроенные SQL-операторы в обычном SQLJ-приложе-
íèè обрабатываются перед исполнением программы специальным
транслятором. Этот этап гарантирует еще одну проверку как правильности используемых SQL-операторов, так и их обращение к базе данных.
В-пятых, везде, где возможно, во встроенных операторах использо-
вание констант можно свободно заменить на переменные Java, используемые в клиентском приложении.
В-шестых, Java-переменным можно присваивать полученные в
результате запроса значения. Полученные значения впоследствии обрабатываются прикладной программой.
В SQLJ-приложениях не требуется никакого приведения типов, в от-
личие от JDBC, где каждую строку результата программист должен явно привести к определенному типу. Также все null значения SQLJ-приложение обрабатывает само.
Далее. В SQLJ не требуется дополнительного кода для работы с
внутренним ресурсами, такими, как операторы освобождения или полученного результата
Также в SQLJ-приложениях не требуется применения оператора
сложения (+) для использования в длинных SQL-строках. При использовании JDBC, приложение при каждом новом соединении с базой данных создает новый объект.
Использование метода close() закрытия сеанса связи происходит для
JDBC- и SQLJ-приложений по-разному. В SQLJ-приложениях метод
close() принадлежит только объекту соединения — ConectionContext.
В момент вызова метода close() все ассоциированные с ним соединения
закроются. В JDBC произойдет полная очистка ресурсов «собирателем
мусора». Это значит, что в случае необходимости необходимо будет заново переустанавливать соединение.
Использование статических операторов позволит избежать предва-
рительной подготовки приложения для обращения к базам данных. Если же применение динамических операторов неизбежно, то существует
несколько достаточно легких способов ускорить выполнение SQL-запроса. Можно использовать статические операторы проведения транзакций
SQL ROLLBACK и COMMIT вместо динамических. Прочие операторы,
кроме SELECT, ROLLBACK и COMMIT, выполняются с помощью

290 Часть 5. Работа с базами данных при помощи Java
EXECUTE IMMEDIATE, а не с помощью стандартных последовательностей PREPARE и EXECUTE.
Наконец, SQLJ позволяет напрямую работать с переменными языка
Java.
Очень многие системные архитекторы пеняют на относительную
медлительность исполнения Java-программ при обращении к базам
данных. Но основная проблема здесь кроется в древнем подходе при создании таблиц базы данных. Еще на заре создания СУБД одним из
основных постулатов было определение для каждой сущности базы
данных отдельной таблицы. Но было красивое решение для старых возможностей. Когда-то и автор был молодым и красивым. На сегодняшний
момент требования к скорости передачи и доступу к данным увеличились в несколько десятков раз, а требования распределенных систем,
таких, как Web, стали напрямую зависеть от скоростных характеристик. И если раньше для клиента создавалась отдельная таблица со
всеми свойственными атрибутами — имя, адрес, количество жен и прочая очень важная информация, — то теперь важнее получить всего
один-два параметра первичной регистрации, а затем уже работать с
другими данными о пользователе. Создание простой таблицы максимум
с тремя полями — Login, password и foreign key — из основной таблицы, описывающей пользователя системы, без использования пресловутого, вездесущего ID, очень любимого системным архитекторами. Использование такой маленькой таблички, лишенной всех дополнительных
атрибутов информации, имеет несколько атрибутов. Во-первых, при регистрации в системе эту таблицу можно расположить в определенной
области памяти. Во-вторых, назначив полю login значение unique, можно еще на один шаг обезопасить систему. Другой шаг обеспечения безопасности заключается в предоставлении определенных правил по работе с данной таблицей, нежели предоставлять для каждого поля определенные права доступа. В-четвертых, данную таблицу очень легко
модифицировать. Все это применимо не только к обычной регистрации
пользователя в системе, но и к использованию идентификационных
карт, дебетовых и кредитных или других регистрационных механизмов.
К чему весь этот длинный монолог? Java не так медлительна, как хо-
телось бы многим системным архитекторам, использующим в повседневной практике VB. Хорошо спроектированная база данных, а значит,
и корректный SQL-запрос украсит не только Java-приложение, но и
VB-приложение или даже PHP-приложения.
Для синхронной передачи, коей является регистрация пользователя,
ускорить процесс можно именно использованием SQLJ. Один маленький
запрос — и проверка на условии равенства! Вот все. Если же, конечно,
попробовать использование JDBC для столь ничтожной операции, то
можно заставить Java работать очень медленно. Автор не против JDBC,
автор за то, чтоб, у каждой женщины был свой муж. Для каждой конкретной цели нужны свои способы достижения. Хорошо, когда их, способов, много, и плохо, когда используется всего один, и то не очень точно. После чего начинаются всякого рода непонимания.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
