[Вопросы для собеседования](README.md) # JDBC + [Что такое _JDBC_?](#Что-такое-jdbc) + [В чем заключаются преимущества использования JDBC?](#В-чем-заключаются-преимущества-использования-jdbc) + [Что из себя представляет JDBC URL?](#Что-из-себя-представляет-jdbc-url) + [Из каких частей стоит JDBC?](#Из-каких-частей-стоит-jdbc) + [Перечислите основные типы данных используемые в JDBC. Как они связаны с типами Java?](#Перечислите-основные-классы-и-интерфейсы-jdbc) + [Опишите основные этапы работы с базой данных с использованием JDBC.](#Опишите-основные-этапы-работы-с-базой-данных-при-использовании-jdbc) + [Как зарегистрировать драйвер JDBC?](#Как-зарегистрировать-драйвер-jdbc) + [Как установить соединение с базой данных?](#Как-установить-соединение-с-базой-данных) + [Какие уровни изоляции транзакций поддерживаются в JDBC?](#Какие-уровни-изоляции-транзакций-поддерживаются-в-jdbc) + [При помощи чего формируются запросы к базе данных?](#При-помощи-чего-формируются-запросы-к-базе-данных) + [Чем отличается Statement от PreparedStatement?](#Чем-отличается-statement-от-preparedstatement) + [Как осуществляется запрос к базе данных и обработка результатов?](#Как-осуществляется-запрос-к-базе-данных-и-обработка-результатов) + [Как вызвать хранимую процедуру?](#Как-вызвать-хранимую-процедуру) + [Как закрыть соединение с базой данных?](#Как-закрыть-соединение-с-базой-данных) ## Что такое _JDBC_? __JDBC, Java DataBase Connectivity (соединение с базами данных на Java)__ — промышленный стандарт взаимодействия Java-приложений с различными СУБД. Реализован в виде пакета `java.sql`, входящего в состав Java SE. JDBC основан на концепции драйверов, которые позволяют получать соединение с базой данных по специально описанному URL. При загрузке драйвер регистрирует себя в системе и в дальнейшем автоматически вызывается, когда программа требует URL, содержащий протокол, за который этот драйвер отвечает. [к оглавлению](#jdbc) ## В чем заключаются преимущества использования JDBC? Преимуществами JDBC считают: + Лёгкость разработки: разработчик может не знать специфики базы данных, с которой работает; + Код практически не меняется, если компания переходит на другую базу данных (количество изменений зависит исключительно от различий между диалектами SQL); + Не нужно дополнительно устанавливать клиентскую программу; + К любой базе данных можно подсоединиться через легко описываемый URL. [к оглавлению](#jdbc) ## Что из себя представляет JDBC URL? __JDBC URL__ состоит из: + `:` (протокола) - всегда `jdbc:`. + `:` (подпротокола) - это имя драйвера или имя механизма соединения с базой данных. Подпротокол может поддерживаться одним или несколькими драйверами. Лежащий на поверхности пример подпротокола - это "odbc", отведенный для URL, обозначающих имя источника данных ODBC. В случае необходимости использовать сервис имен (т.е. имя базы данных в JDBC URL не будет действительным именем базы данных), то подпротоколом может выступать сервис имен. + `` (подимени) - это идентификатор базы данных. Значение подимени может менятся в зависимости от подпротокола, и может также иметь под-подимя с синтаксисом, определяемым разработчиком драйвера. Назначение подимени - это предоставление всей информации, необходимой для поиска базы данных. Например, если база данных находится в Интернет, то в состав подимени JDBC URL должен быть включен сетевой адрес, подчиняющийся следующим соглашениям: `//:/ __NB!__ Сервер базы данных может не поддерживать все уровни изоляции. Интерфейс `java.sql.DatabaseMetaData` предоставляет информацию об уровнях изолированности транзакций, которые поддерживаются данной СУБД. Уровень изоляции транзакции используемый СУБД можно задать с помощью метода `setTransactionIsolation()` объекта `java.sql.Connection`. Получить информацию о применяемом уровне изоляции поможет метод `getTransactionIsolation()`. [к оглавлению](#jdbc) ## При помощи чего формируются запросы к базе данных? Для выполнения запросов к базе данных в Java используются три интерфейса: + `java.sql.Statement` - для операторов SQL без параметров; + `java.sql.PreparedStatement` - для операторов SQL с параметрами и часто выполняемых операторов; + `java.sql.CallableStatement` - для исполнения хранимых в базе процедур. Объекты-носители интерфейсов создаются при помощи методов объекта `java.sql.Connection`: + `java.sql.createStatement()` возвращает объект _Statement_; + `java.sql.prepareStatement()` возвращает объект _PreparedStatement_; + `java.sql.prepareCall()` возвращает объект _CallableStatement_; [к оглавлению](#jdbc) ## Чем отличается Statement от PreparedStatement? + __Statement__: используется для простых случаев запроса без параметров. + __PreparedStatement__: предварительно компилирует запрос, который может содержать входные параметры и выполняться несколько раз с разным набором этих параметров. Перед выполнением СУБД разбирает каждый запрос, оптимизирует его и создает «план» (query plan) его выполнения. Если один и тот же запрос выполняется несколько раз, то СУБД в состоянии кэшировать план его выполнения и не производить этапов разборки и оптимизации повторно. Благодаря этому запрос выполняется быстрее. Суммируя: _PreparedStatement_ выгодно отличается от _Statement_ тем, что при повторном использовании с одним или несколькими наборами параметров позволяет получить преимущества заранее прекомпилированного и кэшированного запроса, помогая при этом избежать SQL Injection. [к оглавлению](#jdbc) ## Как осуществляется запрос к базе данных и обработка результатов? Выполнение запросов осуществляется при помощи вызова методов объекта, реализующего интерфейс `java.sql.Statement`: + __`executeQuery()`__ - для запросов, результатом которых является один набор значений, например запросов `SELECT`. Результатом выполнения является объект класса `java.sql.ResultSet`; + __`executeUpdate()`__ - для выполнения операторов `INSERT`, `UPDATE` или `DELETE`, а также для операторов _DDL (Data Definition Language)_. Метод возвращает целое число, показывающее, сколько записей было модифицировано; + __`execute()`__ – исполняет SQL-команды, которые могут возвращать различные результаты. Например, может использоваться для операции `CREATE TABLE`. Возвращает `true`, если первый результат содержит _ResultSet_ и `false`, если первый результат - это количество модифицированных записей или результат отсутствует. Чтобы получить первый результат необходимо вызвать метод `getResultSet()` или `getUpdateCount()`. Остальные результаты доступны через вызов `getMoreResults()`, который при необходимости может быть произведён многократно. Объект с интерфейсом `java.sql.ResultSet` хранит в себе результат запроса к базе данных - некий набор данных, внутри которого есть курсор, указывающий на один из элементов набора данных - текущую запись. Используя курсор можно перемещаться по набору данных при помощи метода `next()`. > __NB!__ Сразу после получения набора данных его курсор находится перед первой записью и чтобы сделать её текущей необходимо вызвать метод `next()`. Содержание полей текущей записи доступно через вызовы методов `getInt()`, `getFloat()`, `getString()`, `getDate()` и им подобных. [к оглавлению](#jdbc) ## Как вызвать хранимую процедуру? __Хранимые процедуры__ – это именованный набор операторов SQL хранящийся на сервере. Такую процедуру можно вызвать из Java-класса с помощью вызова методов объекта реализующего интерфейс `java.sql.Statement`. Выбор объекта зависит от характеристик хранимой процедуры: + без параметров → `Statement` + с входными параметрами → `PreparedStatement` + с входными и выходными параметрами → `CallableStatement` > Если неизвестно, как была определена хранимая процедура, для получения информации о хранимой процедуре (например, имен и типов параметров) можно использовать методы `java.sql.DatabaseMetaData` позволяющие получить информацию о структуре источника данных. Пример вызова хранимой процедуры с входными и выходными параметрами: ```java public vois runStoredProcedure(final Connection connection) throws Exception { // описываем хранимую процедуру String procedure = "{ call procedureExample(?, ?, ?) }"; // подготавливаем запрос CallableStatement cs = connection.prepareCall(procedure); // устанавливаем входные параметры cs.setString(1, "abcd"); cs.setBoolean(2, true); cs.setInt(3, 10); // описываем выходные параметры cs.registerOutParameter(1, java.sql.Types.VARCHAR); cs.registerOutParameter(2, java.sql.Types.INTEGER); // запускаем выполнение хранимой процедуры cs.execute(); // получаем результаты String parameter1 = cs.getString(1); int parameter2 = cs.getInt(2); // заканчиваем работу с запросом cs.close(); } ``` [к оглавлению](#jdbc) ## Как закрыть соединение с базой данных? Соединение с базой данной закрывается вызовом метода `close()` у соответствующего объекта `java.sql.Connection` или посредством использования механизма try-with-resources при создании такого объекта, появившегося в Java 7. > __NB!__ Предварительно необходимо закрыть все запросы созданные этим соединением. [к оглавлению](#jdbc) # Источники + [Википедия - JDBC](https://ru.wikipedia.org/wiki/Java_Database_Connectivity) + [IBM developerWorks®](http://www.ibm.com/developerworks/ru/library/dm-1209storedprocedures/) + [Документация к пакету java.sql](https://docs.oracle.com/javase/7/docs/api/java/sql/package-summary.html) + [Википедия - Уровень изолированности транзакции](https://ru.wikipedia.org/wiki/Уровень_изолированности_транзакций) [Вопросы для собеседования](README.md)