к оглавлению

Механизм работы c базами данных через JDBC

Базы данных… они повсюду. От них просто нет никакого спасения. Сегодня мало кто не сталкивался с программированием приложений, которые используют базы данных. Начиная от простых (а порой и сложных) текстовых файлов с собственной структурой, заканчивая до боли знакомыми SQL-ориентированными СУБД. Тут собственно разработчики Java не могли остаться в стороне (ну а как иначе?) и написали интерфейс для взаимодействия Java-приложений с базами данных. Тут и далее под базами данных будем понимать СУБД использующие SQL.

Случилось это сравнительно давно. Потому JDBC немного изменился, в лучшую сторону.

Рассматривая данный интерфейс, можно провести параллель с известным DBI/DBD, языка Perl. Сходство весьма заметно. И тот и другой работают по практически идентичной схеме: имея единый интерфейс, подключаем драйвер для работы с определенной СУБД и собственно начинаем писать. Ежели нам нужно сменить СУБД - меняем драйвер. Как это реализовано в Perl, нам пока мало интересно, а вот JDBC рассмотрим поподробнее.

Для начала установим себе драйвер, используемой нами базы данных. Пусть это будет PostgreSQL. Любой JDBC драйвер может представлять собой jar-архив. Для того чтобы из своей программы можно было бы его использовать, нужно, чтобы переменная окружения CLASSPATH содержала путь к нему. Делается это примерно так:

export CLASSPATH=$CLASSPATH:/usr/local/lib/postgresql.jar

Это в том случае, если у вас стоит Linux. В любом другом случае можно обратиться к документации J.

Перейдем непосредственно к использованию нашего JDBC по назначению. Любая программа, которая предполагает использовать JDBC должна импортировать пакеты java.sql.*:



import java.sql.*;

Но при помощи этих пакетов мы не сможем осуществить связь с нашей СУБД. Для этого нам нужен тот самый драйвер, который мы так аккуратно положили в /usr/local/lib/.

Для загрузки/использования нашего драйвера можно пойти двумя путями. Первый – это вписать имя драйвера в код программы. В этом случае мы не сможем изменить СУБД без перекомпиляции. Второй – это подключать драйвер из командной строки Java (JVM).

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

Class.forName(“postgresql.Driver”);

Во втором же случае мы используем ключ –D для подключения драйвера.

java –Djdbc.drivers=postgresql.Driver myClass

Выбирайте любой способ, ориентируясь на то, нужно ли вам будет в дальнейшем переходить на другую СУБД. Если да, то я думаю, второй способ будет предпочтительнее. Особенно для тех, кто пишет программы для широкой публики. А ей свойственно хотеть самим выбирать, чем пользоваться.

Внимание, если вы все сделали одним из этих способов, но при выполнении ваше программы вы получаете ошибку No driver available - это, скорее всего, означает, что вы просто не внесли путь к драйверу в переменную CLASSPATH.

Для соединения с базой данных используют класс Connection:

Connection dbh = DriverManager.getConnection(url, user, passwd);

Здесь url - это строка, по которой JDBC определяет куда, где и чем устанавливать соединение. Она имеет следующий формат:

jdbc:postgresql:база_данных

jdbc:postgresql://сервер/база_данных

jdbc:postgresql://сервер:порт/база_данных

Где сервер – это адрес сервера, где расположена СУБД, порт – это tcp-порт, на котором будет устанавливаться соединение и база_данных – это имя базы данных, которую мы хотим использовать. Следует отметить, что в DBI/DBD эта строчка имела вид:

dbi:postgres:dbname=база_данных;host=сервер;port=порт;

Как видно они очень схожи. Вместо postgres/postgresql может стоять любой, выбранный вами драйвер, для работы с вашей СУБД, например mySQL.

В результате имеем, например:

Connection dbh = DriverManager.getConnection(
"jdbc:postgresql://127.0.0.1/flowers_db","alex","123456"
);

Установив соединение, мы можем выполнять sql-запросы к нашей базе данных. Для примера, рассмотрим небольшой кусок кода на Java:

Statement st = dbh.createStatement();

ResultSet rs = st.executeQuery(
"select * from flowers_tbl where (flowers_id in (1,2,3,4,5,6,7,8,9))"
);

while (rs.next())
{
  System.out.println(rs.getString(1));
}
rs.close();
st.close();

Из этого примера хорошо видно, что для того, чтобы посылать запросы к базе данных, необходимо создать экземпляр класса Statement st. Метод executeQuery этого класса отправляет переданный ему запрос к базе данных и в качестве ответа возвращает результат в виде класса ResultSet.

В общем случае вы можете использовать только один экземпляр класса Statement, если конечно вам по какой-либо серьезной причине не понадобится второй. В случае же работы с потоками, дело обстоит иначе. Здесь обязательно иметь на каждый поток один экземпляр Statement. О потоках речь пойдет в других статьях.

Перед тем как получать данные результата запроса, которые хранятся в нашем случае в переменной rs, необходимо выполнить метод next(). После выполнения этого метода, вы получаете очередную запись виртуально SQL-таблицы ответа на запрос. Метод next() возвращает true, если на запрос были получены данные или еще есть данные в стеке ответа. В противном случаете next() возвращает false.

Ну а метод getString() возвращает строковую переменную, значения поля записи с заданным номером. В нашем случае это 1. После использования результатов переменную rs надо закрыть методом close(), чтобы потом можно было повторно ее использовать для других запросов.

В спецификации JDBC вы можете использовать ResultSet, только один раз последовательно прочитав значения. Это означает, что, взяв однажды значение, вы не можете получить его снова. Для этого лучше использовать дополнительную переменную. Хотя многие драйвера СУБД позволяют снять это ограничения, я все же советую вам использовать вспомогательную переменную, нежели полагаться на драйвер. Это просто накладывает ограничение на переносимость между различными СУБД.

Метод executeQuery() удобен лишь в том случае, когда мы ожидаем ответа от базы данных. Специально для запросов, на которые ответ не обязателен в JDBC был введен еще один метод класса Statement. Это – executeUpdate(). К запросам такого типа относится UPDATE, CREATE, INSERT и пр. С ними можно было познакомиться, прочитав мою статью про SQL в одном из номеров КГ. Приведем пример использования:

st.executeUpdate("create database flowers");
st.executeUpdate("create table flowers_tbl (id integer, name char(25))");

Выше мы рассмотрели возможности JDBC для выполнения SQL-запросов обычным образом. Однако этим возможности JDBC не ограничиваются. Очень многие из них останутся так и не затронутыми в этой статье, о которых вы можете узнать из официальной спецификации JDBC. А нам еще надо рассмотреть возможность предварительной подготовки SQL запросов с последующей подстановкой в них значений. Для этого вместо Statement нужно создать экземпляр класса PreparedStatement:

PreparedStatement ps = dbh.prepareStatement("insert into flowers_tbl values(?,?)");

После чего методом setString() заменяем знаки '?' на значения:

int a = 1;

String b =  "rose";

ps.setString(1,a);
ps.setString(2,b);

И после чего выполняем метод executeUpdate(). Однако, если бы нам нужно было бы вернуть ответ базы данных, то вместо метода executeUpdate() мы используем executeQuery() и тоже без параметров. Вот как это выглядит в обоих случаях:

ps.executeUpdate()

// или

ResultSet rs = ps.exexuteQuery();

Далее вы знаете. Такой механизм в DBI/DBD называется методом курсоров. С другой стороны можно было бы просто сформировать строчку с нужными переменными и выполнить простой Statement, но это куда больше работы, чем с использованием PreparedStatement.

Это все - та малая часть интерфейса JDBC, которая все же позволит вам использовать средства СУБД в своих Java приложениях. Для более детального ознакомления с JDBC я бы посоветовал всем ознакомиться с его спецификацией.



Автор: Алексей Литвинюк


к оглавлению

Знаете ли Вы, что абстракция - это процесс изменения уровня детализации программы. Когда мы абстрагируемся от проблемы, мы предполагаем игнорирование ряда подробностей с тем, чтобы свести задачу к более простой.

НОВОСТИ ФОРУМА

Форум Рыцари теории эфира


Рыцари теории эфира
 10.11.2021 - 12:37: ПЕРСОНАЛИИ - Personalias -> WHO IS WHO - КТО ЕСТЬ КТО - Карим_Хайдаров.
10.11.2021 - 12:36: СОВЕСТЬ - Conscience -> РАСЧЕЛОВЕЧИВАНИЕ ЧЕЛОВЕКА. КОМУ ЭТО НАДО? - Карим_Хайдаров.
10.11.2021 - 12:36: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от д.м.н. Александра Алексеевича Редько - Карим_Хайдаров.
10.11.2021 - 12:35: ЭКОЛОГИЯ - Ecology -> Биологическая безопасность населения - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> Проблема государственного терроризма - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> ПРАВОСУДИЯ.НЕТ - Карим_Хайдаров.
10.11.2021 - 12:34: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вадима Глогера, США - Карим_Хайдаров.
10.11.2021 - 09:18: НОВЫЕ ТЕХНОЛОГИИ - New Technologies -> Волновая генетика Петра Гаряева, 5G-контроль и управление - Карим_Хайдаров.
10.11.2021 - 09:18: ЭКОЛОГИЯ - Ecology -> ЭКОЛОГИЯ ДЛЯ ВСЕХ - Карим_Хайдаров.
10.11.2021 - 09:16: ЭКОЛОГИЯ - Ecology -> ПРОБЛЕМЫ МЕДИЦИНЫ - Карим_Хайдаров.
10.11.2021 - 09:15: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Екатерины Коваленко - Карим_Хайдаров.
10.11.2021 - 09:13: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вильгельма Варкентина - Карим_Хайдаров.
Bourabai Research - Технологии XXI века Bourabai Research Institution