63474

Java DataBase Connectivity. Уровни изолированности транзакций

Лекция

Информатика, кибернетика и программирование

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

Русский

2014-06-20

84 KB

0 чел.

I. Java DataBase Connectivity                                                                                                    Лекция 9.

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

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

con.setTransactionIsolation (TRANSACTION_READ_UNCOMMITTED);

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

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

public int getTransactionIsolation ( ) throws SQLException

TRANSACTION_NONE

Транзакции не поддерживаются.

TRANSACTION_READ_COMMITTED

«Грязное чтение» предотвращается; разовые чтения и фантомные чтения могут происходить. Это уровень препятствует транзакциям от чтения строк с неподтвержденными изменениями в них.

TRANSACTION_READ_UNCOMMITTED

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

TRANSACTION_REPEATABLE_READ

«Грязное чтение» и разовое чтение предотвращаются; фантомные чтения могут происходить. Этот уровень препятствует транзакции от чтения строки с неподтвержденным изменением в ней, он также предотвращает ситуацию, когда одна транзакция читает строку, а вторая транзакция изменяет ее, при этом первая транзакция перечитывая строку, получает разные значения каждый раз (разовое чтение).

TRANSACTION_SERIALIZABLE

«Грязное чтение», разовое чтение и фантомное чтение предотвращаются. Этот уровень включает предотвращения из TRANSACTION_REPEATABLE_READ, более того предотвращает ситуацию, когда одна транзакция читает все строки, которые удовлетворяют условию WHERE, а вторая транзакция вставляет строку, которая удовлетворяет тому же условию WHERE, и первая транзакция, перечитывая с тем же условием, получает дополнительную «фантомную» строку при втором чтении.

PreparedStatement

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

  1.  Экземпляры PreparedStatementпомнятскомпилированые SQL-выражения. Именно поэтому они называются “prepared” ( “подготовленные” ).
  2.  SQL-выражения в PreparedStatement могут иметь один или более (IN) входной параметр. Входной параметр – это параметр, чье значение не указывается при создании SQL-выражения. Вместо него в выражении на месте каждого входного параметра ставится знак (“?”). Значение каждого вопросительного знака устанавливается методами sеtXXX перед выполнением запроса.

Поскольку объекты PreparedStatement прекомпилированы, исполнение этих запросов может происходить несколько быстрее, чем в объектах Statement. В результате SQL-выражения, которые исполняются часто, в целях улучшения производительности создают в виде объектов PreparedStatement. 

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

Создание объектов PreparedStatement

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

PreparedStatement pstmt = con. prepareStatement  (

           “UPDATE table4 SET m = ? WHERE x = ?” );

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

Передача входных ( IN ) параметров  

Перед выполнением объекта PreparedStatement надо установить значения всех его параметров. Это делается с помощью методов setXXX, где XXX – это тип параметра. Например, если параметр имеет Java-тип long, используемый метод будет setLong. Первый аргумент методов setXXX – это порядковый номер параметра, а второй – значение, в которое надо его установить. Например, следующий код устанавливает первый параметр в значение 123456789, a второй – 100000000:

pstmt .steLong ( 1,123456789 );

pstmt .steLong ( 2,100000000 );

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

В режиме соединения по умолчанию (разрешена автофиксация) – каждый запрос фиксируется или откатывается автоматически.

Один и тот же объект PreparedStatement может выполняться много раз, если нижестоящий драйвер или СУБД  будут сохранять выражение (statement) в открытом состоянии даже после того как произойдет фиксация. Иначе не имеет смысла пытаться улучшить производительность заменой на PreparedStatement.

Используя pstmt из предыдущего примера, следующий код устанавливает значение обоих параметров и выполняет pstmt 10 раз. Как уже было отмечено, БД не должна закрывать pstmt. В этом примере первый параметр устанавливается в “Hi” и остается неизменным. Второй параметр устанавливается в последовательные целые значения, начиная от 0 и заканчивая  9.

pstmt.setString (1, “Hi”);

for (int  i = 0; i < 10; i++)    {

         pstmt.setInt (2, i);

         int rowCount = pstmt.executeUpdate ( );

}

Совместимость типов данных входных параметров

ХХХ в названии методов setXXX – это тип данных Java. Неявно он же является и типом данных JDBC (SQL), так как драйвер отображает тип данных Java на соответствующий JDBC-тип передотсылкой JDBC-типа в БД. Следующий код устанавливает второй параметр объекта PreparedStatement pstmt в 44 с типом данных short:

pstmt.setShort (2, 44);

Драйвер отошлет 44 в БД в виде типа JDBC SMALLINT, который является стандартным для Java-типа short.

На программисте лежит ответственность за совместимость Java-типов входных параметров и ожидаемой базой данных соответствующих JDBC-типов. Рассмотрим случай, когда ожидается SMALLINT. Если используется метод setByte, то драйвер отошлет значение TINYINT в БД. Это вероятно, работать будет, так как многие БД преобразуют «похожие» типы данных друг в друга. Тем не менее, чтобы приложение могло работать как можно с большим количеством СУБД, лучше использовать Java-типы, которые в точности соответствуют ожидаемым JDBC-типам. Если ожидается JDBC-тип данных SMALLINT, то использование именно setShort вместо setByte сделает приложение более переносимым.

Использование объектов

Программист может явно задать конвертирование входных параметров в определенный JDBC-тип с помощью метода setObject. Этот тип может принимать третий аргумент, указывающий целевой JDBC-тип данных. Перед отправкой в БД драйвер преобразует Object в указанный JDBC-тип.

Если JDBC-тип не задан, то драйвер просто преобразует Object в его ближайший JDBC-эквивалент, а затем пошлет его в БД.  Это подобно использованию обычных методов setXXX; в обоих случаях драйвер отображает Java-типы в JDBC-типы данных перед отправкой значений в БД.

В случае использования метода setObject тип данных может быть неизвестен приложения на этапе его компиляции. Используя его, приложение может подавать на вход значения любых типов данных и преобразовывать их в ожидаемый базой данных JDBC-тип.

Отсылка значений NULL в качестве входного параметра

Метод setNull позволяет отсылать значения NULL в БД как входные параметры. Хотя JDBC-тип параметра все же можно задать явно.

JDBC-значение NULL будет отослано в БД также в том случае, если методу setXXX будет предано Java-значение null ( если метод принимает Java-объект в качестве аргумента ). Тем не менее, метод setObject может принимать значение null только в том случае, если задан JDBC-тип.

Отправка очень больших входных параметров

Методы setBytes и setString могут отсылать неограниченное количество данных. Правда, иногда программисту легче передавать большие значения в виде маленьких кусков. Это делается установкой входного параметра в значение Java-потока ввода ( input stream ). Когда выполняется выражение, JDBC-драйвер будет производить последовательные вызовы из этого потока ввода, считывая его содержимое и пересылая его в виде значения параметра.

JDBC предоставляет три метода установки входных параметров в поток ввода: setBinaryStream для потоков, содержащих обычные байты, setAsciiStream для потоков ASCII-символов и setUnicodeStream для потоков Unicode-символов. Эти методы, в отличие от остальных методов setXXX, принимают дополнительный аргумент, равный количеству передаваемых в потоке байтов. Этот аргумент необходим, так как некоторые СУБД требуют указания размера данных перед их отсылкой.

Следующий код иллюстрирует отсылку файла в виде входного параметра запроса:

java.io.File file = new java.io.File (“/tmp/data”);

int fileLength = file.length ( );

java.io.InputStream fin = new java.io.FileInputStream (file);

java.sql.PreparedStatement pstmt = con.preparedStatement ( );

           “UPDATE Table 5 SET stuff = ? WHERE index = 4”);

pstmt.setBinaryStream (1, fin, filelength);

pstmt.executeUpdate ( );

При выполнении запроса для доставки данных последовательно считывается поток ввода fin.

CallableStatement (вызываемый оператор)

Объект CallableStatement  предоставляет унифицированный способ вызова хранимых процедур в любой СУБД. Вызов процедуры осуществляется с помощью escape-синтаксиса в одной из двух форм: с результирующим параметром и без него. Результирующий параметр – это один из типов выходных (OUT) параметров, являющийся возвращаемым значением хранимой процедуры. Обе формы могут иметь переменное число аргументов на входе (параметры IN), выходе (параметры OUT) или входных и выходных параметров одновременно (INOUT-параметры). Вопросительный знак означает местоположение параметра.

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

{ call имя_процедуры [ (?, ?, . . .) ] }

Синтаксис для процедуры, возвращающей результат:

{ ? = call имя_процедуры [ (?, ?, . . .) ] }

Синтаксис хранимой процедуры без параметров:

{ call имя_процедуры }

Обычно тот, кто использует объект CallableStatement, уже знает, что используемая СУБД поддерживает хранимые процедуры, и какие именно процедуры имеются в БД. Тем не менее, чтобы это выяснить, достаточно вызвать некоторые методы объекта DatabaseMetaData. Например, метод supportsStoredProcedures возвращает true, если СУБД поддерживает хранимые процедуры, а метод getProcedures возвращает описания доступных процедур.

CallableStatement наследует методы Statement общей для обработки SQL-запросов, а также методы PreparedStatement для обработки входных (IN) параметров. Все методы, объявленные в CallableStatement обрабатывают выходные (OUT) параметры следующим образом: указание JDBC-типов данных (т.е. SQL-типов) выходных параметров, извлечение из них значений или проверка их на NULL.

Создание объекта CallableStatement

Объекты CallableStatement создаются методом prepareCall объекта Connection. Приведем пример, который создает экземпляр CallableStatement, содержащий вызов хранимой процедуры getTestData с двумя аргументами и без возвращаемого параметра:

CallableStatement  cstmt = con.prepareCall ( “ {call  getTestData ( ?, ? ) } “ );

Какими именно параметрами ( IN, OUT или INOUT) являются знаки вопроса – зависит от самой хранимой процедуры getTestData.

IN- и OUT-параметры

Передача значений входных параметров объекта CallableStatement осуществляется с помощью методов setXXX, унаследованных от PreparedStatement. Типы передаваемых значений определяются тем, какой из методов setXXX используется ( setFloat для передачи значений float и т.п.).

JDBC-типы всех OUT-параметров хранимых процедур должны быть зарегистрированы перед их вызовом. Это необходимо, так как некоторым СУБД нужно передавать информацию о типах данных. Регистрация типов данных выходного параметра производится методом registerOutParameter. Только в этом случае после выполнения запроса методы getXXX класса CallableStatement смогут получить значения параметров. Необходимо использовать подходящий по типу данных Java метод getXXX в соответствии с зарегистрированными JDBC-типом параметра. Другими словами,  registerOutParameter используют JDBC-тип ( тот, который подходит к JDBC-типу возвращаемого из БД значения ), а getXXX преобразует его в тип Java.

Приведем пример регистрации выходных параметров, выполнения хранимой процедуры cstmt и считывание параметров. Методов getByte извлекает байт из первого выходного параметра, а getBigDecimal возвращает объект BigDecimal ( с тремя цифрами после десятичной точки ) из второго:

CallableStatement cstmt = con.prepareCall ( “ {call getTestData ( ?, ?) }” );

cstmt. registerOutParameter. (1, java.sql.Types.TINYINT);

cstmt. registerOutParameter. (2, java.sql.Types.DECIMAL, 3);

cstmt.executeQUery ( );

byte x = cstmt.getByte (1);

java.math.BigDecimal n = cstmt.getBigDecimal (2, 3);

В отличие от ResultSet, CallableStatement не может считывать большие значения последовательно (в потоке).

Параметры INOUT

В случае параметра, который одновременно является и входным,  и выходным (INOUT), необходимо вызывать как соответствующий метод setXXX (унаследованный от PreparedStatement), так и метод registerOutParameter. Метод setXXX устанавливает входное значение параметра, а registerOutParameter регистрирует тип выходного значения.

Типы входного и выходного значений, зарегистрированных методом registerOutParameter, должны быть одинаковыми. Для чтения выходного значения используется соответствующий метод getXXX. Например, для параметра типа byte нужно использовать метод установки значения setByte, передавать JDBC-тип данных TINYINT методу registerOutParameter и использовать getByte для чтения выходного значения.

В следующем примере вызывается хранимая процедура reviseTotal с единственным INOUT-параметром. Метод setByte устанавливает значение параметра в 25, которое будет представлено базе данных как TINYINT. Далее метод registerOutParameter регистрирует параметр как TINYINT. После выполнения хранимой процедуры возвращается значение типа TINYINT, которое будет считано методом getByte в виде типа byte языка Java.

CallableStatement cstmt = con.prepareCall ( “ {call revisrTotal ( ? ) }” );

cstmt. setByte (1, 25);

cstmt. registerOutParameter. (1, java.sql.Types.TINYINT);

cstmt.executeUpdate ( );

byte x = cstmt.getByte (1);

Возвращение значения NULL в выходных параметрах

Значение, возвращенное в выходной параметр, может быть NULL. При этом методы getXXX возвращают null, 0 или false, в зависимости от типа данных. Как и в случае с ResultSet, единственным способом узнать, вернула ли процедура 0, false или NULL, является вызов метода wasNull, который возвращает true, если последнее значение, считанное одним из методов getXXX было NULL, и false иначе.


 

А также другие работы, которые могут Вас заинтересовать

47389. Отграничение вандализма от смежных составов преступления 101.77 KB
  В соответствии с ч.1 статьи 214 Уголовного Кодекса Российской Федерации:- вандализм, то есть осквернение зданий или иных сооружений, порча имущества на общественном транспорте или в иных общественных местах,- (наказывается штрафом в размере до 40 тысяч рублей или в размере заработной платы или иного дохода осужденного за период до 3 месяцев, либо обязательными работами на срок от 120 до 180 часов, либо исправительными работами на срок от 6 месяцев до 1 года, либо арестом на срок до 3 месяцев).
47390. Строительство в г. Абакан, расчет и архитектурные особенности 2.07 MB
  Недостатком является стесненность площадки что не позволяет оптимально разместить на ней механизмы и материалы необходимые для проведения работ. Варианты фундаментов: ленточный работающий как балка на упругом основании; столбчатый под колонны. Данный дипломный проект был разработан при помощи ЭВМ. Методы проверки качества маркировка и транспортирование пиломатериалов должно производится по ГОСТ 656463 укладка и хранение – по ГОСТ 3808 поверхностная антисептическая обработка – по ГОСТ 1095064.
47391. Специфика патриотического воспитания дошкольников с отклонениями в эмоционально-личностном развитии и поведении 99.95 KB
  Они делают акцент на приобщение детей к культурному наследию народа. Куликова предлагают одним из решений проблемы воспитания патриотизма детейдошкольников познание ими РодиныРоссии. разработать комплекс занятий для детей с отклонениями направленных на патриотическое воспитание. Уровень патриотического воспитания детей дошкольного возраста с отклонениями в развитии и поведении станет выше если в процессе работы будут использованы игровые словесные наглядные экскурсионные методы и формы функционирования воспитательной системы...
47393. Рисование как средство коррекции недостатков развития умственно отсталых детей 47.16 KB
  Развитие изобразительной деятельности связано с формированием у ребенка активного интереса к окружающему миру и предоставляет возможность ребенку отражать действительность. Лепка является первым основополагающим видом занятий необходимых для умственно отсталого ребенка на начальных этапах формирования изобразительной деятельности. В ходе выполнения аппликаций также создаются условия для формирования целенаправленной деятельности и развития общих интеллектуальных умений.
47394. Управління мотивацією персоналу на підприємстві 849.5 KB
  Сутність поняття мотивація структура мотивації праці. Впровадження бальної системи оплати праці та оцінка її ефективності. В умовах що склалися в Україні на нинішньому етапі її розвитку проблема мотивації персоналу набула важливого значення оскільки вирішення завдань які стоять перед суспільством можливе лише за умови створення належної мотиваційної основи здатної спонукати працівників підприємств до ефективної діяльності. На сьогодні матеріальне стимулювання працівників підприємств як основна складова частина загальної...
47395. Предложения по улучшению финансового состояния ООО ПК «РосМебель» 497.5 KB
  Краткая характеристика предприятия. Общая оценка финансового положения предприятия. Анализ ликвидности предприятия. Анализ деловой активности предприятия.
47396. Особенности развития памяти у младших школьников 759 KB
  Особенности развития памяти у детей младшего школьного возраста. Экспериментальное исследование особенностей развития памяти у младших школьников. Коррекционная работа направленная на развитие памяти.Рекомендации учителям и родителям по развитию памяти младших школьников .
47397. Национальный вопрос в Испании в Новейшее время 426 KB
  Показать борьбу национальных меньшинств за национально-территориальную автономию в 1918-1939 годах; рассмотреть национальную политику режима Франко в 1939-1975 годах; охарактеризовать децентрализацию государственного устройства Испании; выделить политико-правовое положение иммигрантов в Испании