Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лекция 3.2 JDBC

.pdf
Скачиваний:
24
Добавлен:
09.05.2015
Размер:
103.54 Кб
Скачать

Лекция 3.2 JDBC (продолжение)

Предварительно подготовленные команды

Рассмотрим новое средство выполнения запросов — предварительно подготовленные SQL команды. Для этого используется интерфейс PreparedStatement.

Эта возможность существенно повышает эффективность работы. Перед каждым выполнением запроса СУБД создает план его эффективного исполнения. Предварительно подготавливая запрос для последующего многократного повторного использования, можно избежать повторного создания плана.

Интерфейс PreparedStatement наследует от Statement и отличается от последнего следующим:

1.Экземпляры PreparedStatement "помнят" скомпилированные SQL-выражения. Именно поэтому они называются "prepared" ("подготовленные").

2.SQL-выражения в PreparedStatement могут иметь один или более входной (IN) параметр. Входной параметр - это параметр, чье значение не указывается при создании SQL-выражения. Вместо него в выражении на месте каждого входного параметра ставится знак ("?"). Значение каждого вопросительного знака устанавливается методами setXXX перед выполнением запроса. Поскольку объекты PreparedStatement прекомпилированны, исполнение этих запросов может происходить несколько быстрее, чем в объектах Statement. В результате SQL-выражения, которые исполняются часто, в целях улучшения производительности создают в виде объектов PreparedStatement.

Оставаясь подклассом класса Statement, класс PreparedStatement наследует все функции от Statement. В дополнении к ним он добавляет методы установки входных параметров. Кроме того, три метода - execute, executeQuery и executeUpdate - модифицированы таким образом, что не имеют аргументов. Старые методы класса Statement (которые принимают SQL-выражения в качестве единственного аргумента) не должны использоваться в объекте PreparedStatement.

Следующий фрагмент кода, где con - это объект Connection, создает объект PreparedStatement, содержащий SQL-выражение с двумя параметрами:

PreparedStatement pstmt = con.prepareStatement("UPDATE table4 SET m = ? WHERE x = ?");

Объект pstmt отныне содержит выражение "UPDATE table4 SET m = ? WHERE x = ?", которое уже отослано в СУБД и подготовлено для выполнения.

Перед выполнением предварительно подготовленного запроса нужно с помощью метода set() связать подстановочные переменные с их фактическими значениями. Как и при использовании методов get() класса ResultSet, для разных типов данных предусмотрены разные методы set(). Например, следующий код устанавливает первый параметр в значение “Hi”, а второй - в 100:

pstmt.setString(1, "Hi"); pstmt.setInt(2, 100);

При повторном использовании предварительно подготовленного запроса с несколькими подстановочными переменными все связи остаются в силе, если только они не изменены с помощью метода set(). Это значит, что методы set() нужно вызывать толькодля тех подстановочных переменных, которые изменяются в последующих запросах. После установления связи между подстановочными переменными и их фактическими значениями можно приступать к выполнению запроса.

pstmt.setString(1, "Hi");

for (int i = 0; i < 10; i++) { pstmt.setInt(2, i);

int rowCount = pstmt.executeUpdate();

}

Используя pstmt из предыдущего примера, следующий код устанавливает значения обоих параметров и выполняет подготовленныей запрос "UPDATE table4 SET m = ? WHERE x = ?" 10 раз. Как уже было отмечено, БД не должна закрывать pstmt. В этом примере первый параметр устанавливается в "Hi" и остается неизменным. Второй параметр устанавливается в последовательные целые значения, начиная от 0 и заканчивая 9. Метод executeUpdate() возвращает лишь счетчик обновленных записей.

Некоторые программисты Java стараются избегать создания сложных SQL команд. Как ни странно, но они склонны делать тот же самое с помощью Java кода, причем при этом приходится обрабатывать несколько наборов результатов. Учтите, что СУБД выполняет запросы гораздо эффективнее, чем Java программа, поскольку СУБД оптимизирована для этой цели. Помните основное правило: то, что можно сделать средствами SQL, не следует делать средствами Java.

Транзакции

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

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

По умолчанию соединение с базой данных обладает возможностью автоматической фиксации (autocommit mode), т.е. каждая SQL команда фиксируется после ее успешного выполнения. Причем зафиксированную команду нельзя отвергнуть.

Для проверки текущего режима автоматической фиксации нужно вызвать метод getAutoCommit() класса Connection. Для отключения режима автоматической фиксации используется метод

con.setAutoCommit(false);

Отключив автоматическую фиксацию, можно приступать к созданию объекта Statement.

Statement stat = conn.createStatement();

Затем нужное количество раз вызывается метод executeUpdate().

stat.executeUpdate(command1);

stat.executeUpdate(command2);

stat.executeUpdate(command3);

...

После выполнения всех этих команд необходимо вызвать метод commit().

conn.commit();

В случае возникновения какой либо ошибки нужно отвергнуть все предыдущие команды (кроме commit) c помощью метода rollback().

conn.rollback();

Откат обычно производится, если при выполнении транзакции генерируется исключение

SQLException.

Точки сохранения

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

Statement stat = conn.createStatement(); // начало транзации, в эту точку осуществляется переход при вызове rollback()

stat.executeUpdate(command1);

Savepoint svpt = conn.setSavepoint(); // установка точки сохранения, в неё осуществляется переход при вызове rollback(svpt)

stat.executeUpdate(command2);

if (. . .) conn.rollback(svpt); // отмена command2

. . .

conn.commit();

Здесь мы используем неименованную, или анонимную, точку сохранения. Точке сохранения можно присвоить имя.

Savepoint svpt = conn.setSavepoint("stage1");

Если точка сохранения не нужна, ее следует отменить.

stat.releaseSavepoint(svpt);