gadget59.ru практика
Базы данных · Практика 2 · 28 слайдов

Практическая работа: подключение Java к MS SQL Server через JDBC

Java + MS SQL Server через JDBC

Мы научились работать с базой данных «Библиотека» вручную — через программу SQL Server Management Studio (SSMS, программа для работы с MS SQL Server). Но настоящие приложения работают с базой программно. Именно этим займёмся сегодня.

☕ Java 🪟 MS SQL Server 🔌 JDBC 📦 mssql-jdbc 🔗 Connection 📋 ResultSet
Мы напишем консольное Java-приложение, которое подключается к нашей базе «Библиотека», читает книги, читателей и выдачи, а также добавляет новых читателей через безопасный PreparedStatement.
Формат: практическая работа, 2 академических часа. Понадобится IDE (интегрированная среда разработки, например IntelliJ IDEA или VS Code), JDK и база «Библиотека» из Практики 1.

План практики

Сегодня мы пройдём путь от «что такое JDBC» до работающего Java-приложения.

  • 1 Что такое JDBC и зачем нужен драйвер
  • 2 Что нужно для подключения
  • 3 Скачиваем драйвер mssql-jdbc
  • 4 Подключаем драйвер к проекту
  • 5 Первое подключение к базе
  • 6 Чтение данных: Statement + ResultSet
  • 7 Добавление данных: PreparedStatement
  • 8 Почему PreparedStatement безопаснее
  • 9 Собираем консольное приложение
  • 10 Обработка ошибок и типичные проблемы
  • 11 Практика и домашнее задание
Если Практика 1 не сделана — сначала создайте базу «Библиотека». Без неё эта работа не имеет смысла.

Что такое JDBC?

JDBC (Java Database Connectivity, «связь Java с базами данных») — это стандартный интерфейс Java для работы с реляционными базами данных.

Java-программа
→
JDBC
→
Драйвер
→
MS SQL Server
  • JDBC — это набор классов и интерфейсов в пакете java.sql. Они входят в стандартную поставку JDK (Java Development Kit, комплект разработчика Java).
  • Драйвер — это отдельная библиотека, которая «переводит» команды JDBC на язык конкретной базы данных.
  • Для MS SQL Server драйвер называется mssql-jdbc. Его нужно скачать отдельно.
JDBC — это «универсальный разъём». Java-код не меняется при переходе с MS SQL Server на PostgreSQL или MySQL. Меняется только драйвер.

Что нужно для подключения

Чтобы подключиться к MS SQL Server из Java, нужно четыре вещи.

☕
JDK
Комплект разработчика Java (версия 8 или новее).
🪟
MS SQL Server
Запущенный сервер с базой LibraryDB (из Практики 1).
📦
Драйвер mssql-jdbc
JAR-файл с драйвером. JAR — это Java Archive, архив Java-классов.
💻
IDE
IntelliJ IDEA, Eclipse или VS Code — где вы пишете код.
Если база «Библиотека» не создана — вернитесь к Практике 1. Без неё мы не сможем читать и писать данные.

Скачиваем драйвер mssql-jdbc

Драйвер mssql-jdbc — это JAR-файл, который нужно добавить в проект. Есть два способа: через систему сборки Maven (популярный инструмент сборки Java-проектов) или вручную.

Способ 1. Maven (если проект на Maven)

Добавьте в файл pom.xml:

<!-- pom.xml --> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>12.6.1.jre11</version> </dependency>

Maven сам скачает драйвер и все его зависимости.

Способ 2. Вручную

  1. Скачайте JAR-файл с официального сайта Microsoft.
  2. Положите его в папку lib/ проекта.
  3. В IDE добавьте его в classpath: «Project Structure → Libraries → Add JAR».
Maven — самый простой способ. Он сам следит за версиями и зависимостями.

Структура Java-проекта

Создадим стандартную структуру Java-проекта.

// Структура проекта library-jdbc/ ├── src/ │ └── ru/ │ └── gadget59/ │ └── library/ │ ├── Main.java │ └── DatabaseHelper.java ├── lib/ // сюда кладём mssql-jdbc.jar (если вручную) │ └── mssql-jdbc.jar └── pom.xml // если проект на Maven
  • src/ — исходный код.
  • ru/gadget59/library — пакет проекта (соглашение об именах — домен в обратном порядке + назначение).
  • lib/ — сторонние библиотеки (JAR-файлы).
Пакет ru.gadget59.library — это пространство имён. Внутри него лежат наши классы. Имя пакета совпадает со структурой папок — это требование Java.

Строка подключения (Connection URL)

Чтобы Java нашла базу данных, ей нужна строка подключения (connection URL, Uniform Resource Locator — универсальный адрес ресурса).

// Строка подключения к MS SQL Server String url = "jdbc:sqlserver://localhost\\SQLEXPRESS;" + "databaseName=LibraryDB;" + "encrypt=false;";
ЧастьЧто значитПример jdbc:sqlserver://протокол и СУБДобязательно localhostимя сервералокальный компьютер \SQLEXPRESSимя экземпляраесли Express-версия databaseName=LibraryDBимя базы данныхнаша база encrypt=falseшифрование соединениядля локальной разработки
Если у вас не Express-версия, а полноценный MS SQL Server, имя экземпляра может быть другим. Проверьте это в SSMS или в «Службах» Windows.

Первое подключение

Напишем минимальную программу, которая просто проверяет, что подключение работает.

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class Main { public static void main(String[] args) { String url = "jdbc:sqlserver://localhost\\SQLEXPRESS;" + "databaseName=LibraryDB;encrypt=false;"; try (Connection conn = DriverManager.getConnection(url)) { if (conn != null) { System.out.println("Подключение успешно!"); } } catch (SQLException e) { System.out.println("Ошибка: " + e.getMessage()); } } }
Если в консоли появилось «Подключение успешно!» — Java нашла базу данных. Это первый большой шаг.
Если ошибка «No suitable driver» — не подключён драйвер. Проверьте Maven или папку lib/.

Что такое Connection

Connection (соединение) — это объект, который представляет активное подключение к базе данных.

Java
→
Connection
→
База данных
  • Один Connection = одно соединение с базой.
  • Через него отправляются SQL-запросы.
  • В конце работы Connection нужно закрыть.
Мы использовали конструкцию try (Connection conn = ...). Это специальный синтаксис Java — «try-with-resources», который автоматически закрывает соединение, когда мы выходим из блока. Мы разбирали его в лекции про исключения.
Всегда используйте try-with-resources. Тогда не забудете закрыть соединение — и не будет «утечек» ресурсов.

Чтение данных: Statement и ResultSet

Прочитать данные из базы можно через Statement (запрос) и ResultSet (результат).

import java.sql.*; public class ReadBooks { public static void main(String[] args) { String url = "jdbc:sqlserver://localhost\\SQLEXPRESS;" + "databaseName=LibraryDB;encrypt=false;"; try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement()) { ResultSet rs = stmt.executeQuery( "SELECT Title, Year FROM Books ORDER BY Year"); while (rs.next()) { String title = rs.getString("Title"); int year = rs.getInt("Year"); System.out.println(title + " (" + year + ")"); } } catch (SQLException e) { e.printStackTrace(); } } }
В консоли появятся все книги из таблицы Books, отсортированные по году.

Как работает ResultSet

ResultSet (набор результатов) — это таблица с результатами SELECT-запроса.

TitleYear Евгений Онегин1833 Война и мир1869 Анна Каренина1877
  • rs.next() — перейти на следующую строку. Возвращает false, когда строки закончились.
  • rs.getString("Title") — прочитать столбец «Title» из текущей строки.
  • rs.getInt("Year") — прочитать целочисленный столбец.
  • Можно читать и по индексу: rs.getString(1) — первый столбец. Но по имени надёжнее.
ResultSet — это «курсор». Он указывает на одну строку за раз. Мы двигаем его через next().

Добавление данных: INSERT

Для добавления данных используется метод executeUpdate и команда INSERT.

try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement()) { String sql = "INSERT INTO Authors (Name, Country) " + "VALUES (N'Михаил Булгаков', N'Россия')"; int rows = stmt.executeUpdate(sql); System.out.println("Добавлено строк: " + rows); }
МетодКогда использоватьЧто возвращает executeQueryдля SELECTResultSet executeUpdateдля INSERT, UPDATE, DELETEколичество затронутых строк
В примере мы склеиваем SQL из строк. Для учебного примера это допустимо, но так делать нельзя, если значения приходят от пользователя. Об этом — следующий слайд.

Проблема: SQL-инъекция

SQL-инъекция — это атака, при которой злоумышленник подставляет в SQL-запрос хитрую строку и получает доступ к данным, к которым не должен.

Пример уязвимого кода

String name = Scanner.nextLine(); // вводит пользователь // ОПАСНО: склеиваем строку с вводом пользователя String sql = "SELECT * FROM Readers WHERE Name = '" + name + "'";

Что может ввести злоумышленник

' OR '1'='1

Тогда SQL-запрос станет таким:

SELECT * FROM Readers WHERE Name = '' OR '1'='1';
Условие '1'='1' всегда истинно. Запрос вернёт всех читателей, а не одного. Так хакеры крадут пароли, банковские данные и личную информацию.

Решение: PreparedStatement

PreparedStatement (подготовленный запрос) — это способ отправки SQL-запроса, при котором значения передаются отдельно от команд SQL.

String sql = "SELECT * FROM Readers WHERE Name = ?"; try (Connection conn = DriverManager.getConnection(url); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, name); // значение подставляется безопасно ResultSet rs = ps.executeQuery(); while (rs.next()) { System.out.println(rs.getString("Name")); } }
МетодТипПример setStringстрокаsetString(1, "Иван") setIntцелое числоsetInt(1, 25) setDateдатаsetDate(1, Date.valueOf("2026-10-24")) setNullпустое значениеsetNull(1, Types.INTEGER)
Java автоматически экранирует введённые значения. Даже если пользователь введёт ' OR '1'='1, это будет воспринято как обычный текст, а не как команда SQL.

INSERT через PreparedStatement

PreparedStatement используется не только для SELECT, но и для INSERT, UPDATE, DELETE.

String sql = "INSERT INTO Readers (Name, Email, Registered) " + "VALUES (?, ?, ?)"; try (Connection conn = DriverManager.getConnection(url); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, "Алексей Смирнов"); ps.setString(2, "alex@mail.ru"); ps.setDate(3, Date.valueOf("2026-10-25")); int rows = ps.executeUpdate(); System.out.println("Добавлено: " + rows); }
? — это «дырка» в запросе, куда будет подставлено значение.
setString(1, ...) — подставить строку в первую дырку.
setInt(2, ...) — подставить число во вторую.
Нумерация начинается с 1, а не с 0!

SELECT с условием через PreparedStatement

Найдём все книги конкретного автора, подставив имя через параметр.

String sql = "SELECT b.Title, b.Year " + "FROM Books b " + "INNER JOIN Authors a ON b.AuthorId = a.Id " + "WHERE a.Name = ?"; try (Connection conn = DriverManager.getConnection(url); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, "Лев Толстой"); ResultSet rs = ps.executeQuery(); while (rs.next()) { System.out.println( rs.getString("Title") + " (" + rs.getInt("Year") + ")"); } }
В консоли появятся «Война и мир (1869)» и «Анна Каренина (1877)».

Собираем всё вместе: DatabaseHelper

Хорошая практика — вынести подключение и общие методы в отдельный класс.

package ru.gadget59.library; import java.sql.*; public class DatabaseHelper { private static final String URL = "jdbc:sqlserver://localhost\\SQLEXPRESS;" + "databaseName=LibraryDB;encrypt=false;"; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL); } }
Теперь в любом месте программы можно написать DatabaseHelper.getConnection() — и получить соединение. Это удобно и безопасно.
В реальных проектах строку подключения выносят в файл конфигурации. Но для учебного проекта достаточно константы.

Метод «показать все книги»

Добавим в DatabaseHelper метод, который выводит все книги с авторами.

public static void showAllBooks() { String sql = "SELECT b.Title, b.Year, a.Name AS AuthorName " + "FROM Books b " + "INNER JOIN Authors a ON b.AuthorId = a.Id " + "ORDER BY a.Name, b.Year"; try (Connection conn = getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { System.out.printf("%-30s | %-25s | %d%n", rs.getString("Title"), rs.getString("AuthorName"), rs.getInt("Year")); } } catch (SQLException e) { e.printStackTrace(); } }
System.out.printf — это форматированный вывод. %-30s означает «строка, выровненная по левому краю, шириной 30 символов».

Метод «добавить читателя»

Добавим метод, который безопасно вставляет нового читателя.

public static void addReader(String name, String email, String date) { String sql = "INSERT INTO Readers (Name, Email, Registered) " + "VALUES (?, ?, ?)"; try (Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, name); ps.setString(2, email); ps.setDate(3, Date.valueOf(date)); ps.executeUpdate(); System.out.println("Читатель добавлен: " + name); } catch (SQLException e) { e.printStackTrace(); } }
Теперь в главном классе можно вызвать DatabaseHelper.addReader("Алексей", "alex@mail.ru", "2026-10-25"), и читатель появится в базе.

Метод «активные читатели»

Найдём читателей, которые взяли больше одной книги.

public static void showActiveReaders() { String sql = "SELECT r.Name, COUNT(l.Id) AS LoanCount " + "FROM Readers r " + "LEFT JOIN Loans l ON l.ReaderId = r.Id " + "GROUP BY r.Name " + "HAVING COUNT(l.Id) > 1"; try (Connection conn = getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { System.out.println( rs.getString("Name") + " — " + rs.getInt("LoanCount") + " книг"); } } catch (SQLException e) { e.printStackTrace(); } }
Мы использовали Statement, потому что в запросе нет пользовательских значений. Для запросов с параметрами лучше PreparedStatement.

Главный класс

Соберём всё вместе в главном классе.

package ru.gadget59.library; public class Main { public static void main(String[] args) { System.out.println("=== Все книги с авторами ==="); DatabaseHelper.showAllBooks(); System.out.println("\n=== Активные читатели ==="); DatabaseHelper.showActiveReaders(); System.out.println("\n=== Добавляем нового читателя ==="); DatabaseHelper.addReader( "Алексей Смирнов", "alex@mail.ru", "2026-10-25"); System.out.println("\n=== Проверяем, что читатель добавился ==="); DatabaseHelper.showAllReaders(); } }
Программа выведет все книги, всех активных читателей, добавит нового читателя и покажет обновлённый список.

Правила безопасного кода с JDBC

Запомните эти правила — они уберегут вас от большинства проблем.

  1. Всегда используйте PreparedStatement, если в запросе есть значения от пользователя. Никаких склеек строк.
  2. Всегда закрывайте Connection, Statement и ResultSet через try-with-resources.
  3. Не храните пароли в коде. Пароль к базе — только в файле конфигурации.
  4. Не выводите данные в консоль в продакшене. Используйте логгер.
  5. Обрабатывайте SQLException. Пользователь должен видеть понятное сообщение об ошибке.
  6. Не открывайте лишних соединений. Если можно переиспользовать — переиспользуйте.
SQL-инъекция — это не теоретическая угроза. Каждый год хакеры крадут миллионы записей через уязвимые формы на сайтах. PreparedStatement — это не «хорошая практика», это обязательное требование.

Типичные ошибки

1. No suitable driver
Драйвер не подключён. Проверьте Maven или папку lib/.
2. Login failed for user
Проблема с правами. Для локальной разработки используйте Windows Authentication.
3. The TCP/IP connection has failed
SQL Server не принимает TCP-подключения. Проверьте настройки в SQL Server Configuration Manager.
4. Invalid object name 'Books'
Таблица не найдена. Проверьте, что вы выполнили USE LibraryDB.
5. The conversion of a varchar data type...
Проблема с кодировкой. Используйте NVARCHAR и N перед русскими строками.
6. Connection is closed
Соединение уже закрыто. Проверьте, что вы не используете его после закрытия.

Практический результат

Вот что вы получите, если выполните все шаги.

// Ожидаемый вывод программы === Все книги с авторами === Евгений Онегин | Александр Пушкин | 1833 Война и мир | Лев Толстой | 1869 Анна Каренина | Лев Толстой | 1877 Гарри Поттер... | Джоан Роулинг | 1997 Оно | Стивен Кинг | 1986 Сияние | Стивен Кинг | 1977 === Активные читатели === Иван Петров — 2 книг Мария Сидорова — 2 книг === Добавляем нового читателя === Читатель добавлен: Алексей Смирнов === Проверяем, что читатель добавился === Иван Петров Мария Сидорова Пётр Иванов Ольга Смирнова Алексей Смирнов
Вы написали настоящее Java-приложение, работающее с настоящей базой данных.

Самостоятельные задания

Попробуйте дописать эти методы самостоятельно.

  1. Метод showAllReaders() — вывести всех читателей с email и датой регистрации.
  2. Метод showBooksByAuthor(String authorName) — книги конкретного автора через PreparedStatement.
  3. Метод showUnreturnedBooks() — книги, которые ещё не вернули (через IS NULL).
  4. Метод addLoan(int bookId, int readerId) — оформить выдачу книги читателю.
  5. Метод returnLoan(int loanId) — отметить книгу возвращённой (установить ReturnDate).
  6. Метод showTopReaders() — топ-3 читателя по количеству взятых книг.
Для UPDATE используйте executeUpdate. Для SELECT — executeQuery.

Итоги практики

Подведём итоги. Вот что вы теперь умеете.

  • ✅ JDBC — стандартный интерфейс Java для работы с базами данных.
  • ✅ Драйвер mssql-jdbc — библиотека, связывающая Java с MS SQL Server.
  • ✅ Connection — объект подключения к базе.
  • ✅ Statement — простой запрос без параметров.
  • ✅ PreparedStatement — безопасный запрос с параметрами.
  • ✅ ResultSet — результат SELECT-запроса.
  • ✅ executeQuery — для SELECT, executeUpdate — для INSERT, UPDATE, DELETE.
  • ✅ SQL-инъекция — угроза, от которой защищает PreparedStatement.
  • ✅ try-with-resources — автоматическое закрытие ресурсов.
Теперь вы можете связать Java-приложение с любой реляционной базой данных. Это ключевой навык для backend-разработчика.

Домашнее задание

Задания для самостоятельной работы. Первые три обязательны, остальные — для оценки «отлично».

  1. Реализуйте все методы из слайда «Самостоятельные задания».
  2. Добавьте обработку ошибок: пользователь не должен видеть стек-трейс. Только понятное сообщение.
  3. Добавьте метод findReaderByEmail(String email) через PreparedStatement.
  4. Создайте консольное меню: пользователь выбирает действие (показать книги, добавить читателя, выдать книгу и т.д.).
  5. Добавьте логирование SQL-запросов в консоль (какой запрос выполняется).
  6. Попробуйте SQL-инъекцию на своём коде и убедитесь, что PreparedStatement её блокирует.
Если задание кажется сложным — разбейте его на части. Один метод = одна задача.

Спасибо за работу!

🔌

Java умеет говорить с базой данных!

Вы прошли весь путь: от пустого окна SSMS до Java-приложения, которое читает и пишет данные. Это полноценный backend-навык.

☕ Java 🔌 JDBC 🪟 MS SQL Server 🛡️ PreparedStatement 🚀 backend