+ [Перечислите основные типы данных используемые в JDBC. Как они связаны с типами Java?](#Перечислите-основные-типы-данных-используемые-в-JDBC.-Как-они-связаны-с-типами-Java)
__JDBC, Java DataBase Connectivity (соединение с базами данных на Java)__ — промышленный стандарт взаимодействия Java-приложений с различными СУБД. Реализован в виде пакета `java.sql`, входящего в состав Java SE.
JDBC основан на концепции драйверов, которые позволяют получать соединение с базой данных по специально описанному URL. При загрузке драйвер регистрирует себя в системе и в дальнейшем автоматически вызывается, когда программа требует URL, содержащий протокол, за который этот драйвер отвечает.
+ Лёгкость разработки: разработчик может не знать специфики базы данных, с которой работает;
+ Код практически не меняется, если компания переходит на другую базу данных (количество изменений зависит исключительно от различий между диалектами SQL);
+ Не нужно дополнительно устанавливать клиентскую программу;
+ К любой базе данных можно подсоединиться через легко описываемый URL.
+ `<subprotocol>:` (подпротокола) - это имя драйвера или имя механизма соединения с базой данных. Подпротокол может поддерживаться одним или несколькими драйверами. Лежащий на поверхности пример подпротокола - это "odbc", отведенный для URL, обозначающих имя источника данных ODBC. В случае необходимости использовать сервис имен (т.е. имя базы данных в JDBC URL не будет действительным именем базы данных), то подпротоколом может выступать сервис имен.
+ `<subname>` (подимени) - это идентификатор базы данных. Значение подимени может менятся в зависимости от подпротокола, и может также иметь под-подимя с синтаксисом, определяемым разработчиком драйвера. Назначение подимени - это предоставление всей информации, необходимой для поиска базы данных. Например, если база данных находится в Интернет, то в состав подимени JDBC URL должен быть включен сетевой адрес, подчиняющийся следующим соглашениям: `//<hostname>:<port>/<subsubname`.
Пример JDBC URL для подключения к MySQL базе данных «Test» расположенной по адресу localhost и ожидающей соединений по порту 3306: `jdbc:mysql://localhost:3306/Test`
+ __JDBC API__, который содержит набор классов и интерфейсов, определяющих доступ к базам данных. Эти классы и методы объявлены в двух пакетах - `java.sql` и `javax.sql`;
+ __JDBC-драйвер__, компонент, специфичный для каждой базы данных.
JDBC превращает вызовы уровня API в «родные» команды того или иного сервера баз данных.
+ `java.sql.DriverManager` - позволяет загрузить и зарегистрировать необходимый JDBC-драйвер, а затем получить соединение с базой данных.
+ `javax.sql.DataSource` - решает те же задачи, что и _DriverManager_, но более удобным и универсальным образом. Существуют также `javax.sql.ConnectionPoolDataSource` и `javax.sq1.XADataSource` задача которых - обеспечение поддержки пула соединений.
+ `java.sql.Connection` - обеспечивает формирование запросов к источнику данных и управление транзакциями. Также предусмотрены интерфейсы `javax.sql.PooledConnection` и `javax.sql.XAConnection`.
В результате вызова будет установлено соединение с базой данных и создан объект класса `java.sql.Connection` - своеобразная «сессия», внутри контекста которой и будет происходить дальнейшая работа с базой данных.
__Уровень изолированности транзакций__ — значение, определяющее уровень, при котором в транзакции допускаются несогласованные данные, то есть степень изолированности одной транзакции от другой. Более высокий уровень изолированности повышает точность данных, но при этом может снижаться количество параллельно выполняемых транзакций. С другой стороны, более низкий уровень изолированности позволяет выполнять больше параллельных транзакций, но снижает точность данных.
Во время использования транзакций, для обеспечения целостности данных, СУБД использует блокировки, чтобы заблокировать доступ других обращений к данным, участвующим в транзакции. Такие блокировки необходимы, чтобы предотвратить:
+ _«грязное» чтение (dirty read)_ — чтение данных, добавленных или изменённых транзакцией, которая впоследствии не подтвердится (откатится);
+ _неповторяющееся чтение (non-repeatable read)_ — при повторном чтении в рамках одной транзакции ранее прочитанные данные оказываются изменёнными;
+ _фантомное чтение (phantom reads)_ — ситуация, когда при повторном чтении в рамках одной транзакции одна и та же выборка дает разные множества строк.
Уровни изоляции транзакций определены в виде констант интерфейса `java.sql.Connection`:
+ `TRANSACTION_READ_UNCOMMITTED`– позволяет транзакциям видеть несохраненные изменения данных: разрешает грязное, непроверяющееся и фантомное чтения;
+ `TRANSACTION_READ_COMMITTED`– любое изменение, сделанное в транзакции, не видно вне неё, пока она не сохранена: предотвращает грязное чтение, но разрешает непроверяющееся и фантомное;
+ `TRANSACTION_REPEATABLE_READ`– запрещает грязное и непроверяющееся, фантомное чтение разрешено;
+ `TRANSACTION_SERIALIZABLE`– грязное, непроверяющееся и фантомное чтения запрещены.
> __NB!__ Сервер базы данных может не поддерживать все уровни изоляции. Интерфейс `java.sql.DatabaseMetaData` предоставляет информацию об уровнях изолированности транзакций, которые поддерживаются данной СУБД.
Уровень изоляции транзакции используемый СУБД можно задать с помощью метода `setTransactionIsolation()` объекта `java.sql.Connection`. Получить информацию о применяемом уровне изоляции поможет метод `getTransactionIsolation()`.
+ __Statement__: используется для простых случаев запроса без параметров.
+ __PreparedStatement__: предварительно компилирует запрос, который может содержать входные параметры и выполняться несколько раз с разным набором этих параметров.
Перед выполнением СУБД разбирает каждый запрос, оптимизирует его и создает «план» (query plan) его выполнения. Если один и тот же запрос выполняется несколько раз, то СУБД в состоянии кэшировать план его выполнения и не производить этапов разборки и оптимизации повторно. Благодаря этому запрос выполняется быстрее.
Суммируя: _PreparedStatement_ выгодно отличается от _Statement_ тем, что при повторном использовании с одним или несколькими наборами параметров позволяет получить преимущества заранее прекомпилированного и кэшированного запроса, помогая при этом избежать SQL Injection.
Выполнение запросов осуществляется при помощи вызова методов объекта, реализующего интерфейс `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()` и им подобных.
__Хранимые процедуры__ – это именованный набор операторов SQL хранящийся на сервере. Такую процедуру можно вызвать из Java-класса с помощью вызова методов объекта реализующего интерфейс `java.sql.Statement`.
Выбор объекта зависит от характеристик хранимой процедуры:
+ без параметров → `Statement`
+ с входными параметрами → `PreparedStatement`
+ с входными и выходными параметрами → `CallableStatement`
> Если неизвестно, как была определена хранимая процедура, для получения информации о хранимой процедуре (например, имен и типов параметров) можно использовать методы `java.sql.DatabaseMetaData` позволяющие получить информацию о структуре источника данных.
Пример вызова хранимой процедуры с входными и выходными параметрами:
```java
public vois runStoredProcedure(final Connection connection) throws Exception {
Соединение с базой данной закрывается вызовом метода `close()`у соответствующего объекта `java.sql.Connection` или посредством использования механизма try-with-resources при создании такого объекта, появившегося в Java 7.
> __NB!__ Предварительно необходимо закрыть все запросы созданные этим соединением.