Hibernate и JPA — практический старт
Hibernate и JPA — практический старт
JPA (Jakarta Persistence API) — стандарт ORM: работа с БД через объекты. Hibernate — основная реализация JPA в Java.
В Spring Boot обычно используют Spring Data JPA, а не EntityManager вручную.
База Spring: Первая программа на Spring · обзор ORM: Экосистема Java-приложений · Spring Framework.
Зависимости (Maven)
В start.spring.io выберите: Spring Web, Spring Data JPA, H2 Database.
Или в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Разбор:
- этот XML-блок описывает конфигурацию сборки, которую инструмент считывает до выполнения прикладного Java-кода.
- элементы с артефактами
spring-boot-starter-data-jpa,h2включают нужные библиотеки и определяют доступные API в кодовой базе. - секция
<scope>test</scope>ограничивает зависимость тестовым контуром и не тащит ее в production-артефакт. - любое изменение здесь влияет на classpath и поведение сборки, поэтому такие правки проверяют полным прогоном тестов.
- после редактирования этого фрагмента проверяют, что проект собирается и тестовый раннер видит нужные классы без конфликтов версий.
application.properties:
spring.datasource.url=jdbc:h2:mem:notes
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Разбор:
- блок задает runtime-конфигурацию приложения, и эти параметры читаются фреймворком при старте контекста.
- ключи
spring.datasource.url,spring.h2.console.enabled,spring.jpa.hibernate.ddl-auto,spring.jpa.show-sqlуправляют подключением к БД, режимом генерации схемы и диагностическим выводом SQL. - изменение значений здесь мгновенно меняет поведение приложения без правок Java-классов.
- такие параметры важно разделять по окружениям (dev/test/prod), чтобы безопасные настройки разработки не ушли в production.
- корректность проверяется запуском приложения и фактическим поведением: подключение к БД, миграции и ожидаемые логи.
Сущность
Код ITЗагрузка примера кода…
Разбор:
- фрагмент показывает прикладной сценарий по теме раздела: здесь есть входные данные, операции над ними и проверяемый итог.
- аннотации
Entity,Table,Id,GeneratedValue,Columnвключают поведение фреймворка (тестовый раннер, web-маршрутизация, ORM или транзакционные правила). - ключевые вызовы
Table,GeneratedValue,Column,Note,getId,getText,setTextзадают основную механику этого примера: обработку, проверку и формирование результата. - чтение этого блока по шагам дает предсказуемую картину — сначала подготовка данных, затем действие API, затем получение конечного значения.
- после запуска стоит проверить именно эффект этого примера — вывод, значение переменной, статус ответа, состояние БД или результат теста.
- при переносе в production обычно добавляют валидацию входа, явную обработку ошибок и тест на граничные случаи вокруг этого сценария.
Репозиторий
package com.example.notes;
import org.springframework.data.jpa.repository.JpaRepository;
public interface NoteRepository extends JpaRepository<Note, Long> {
}
Разбор:
- фрагмент показывает прикладной сценарий по теме раздела: здесь есть входные данные, операции над ними и проверяемый итог.
- чтение этого блока по шагам дает предсказуемую картину — сначала подготовка данных, затем действие API, затем получение конечного значения.
- после запуска стоит проверить именно эффект этого примера — вывод, значение переменной, статус ответа, состояние БД или результат теста.
- при переносе в production обычно добавляют валидацию входа, явную обработку ошибок и тест на граничные случаи вокруг этого сценария.
Spring Data сгенерирует save, findAll, findById, deleteById без реализации.
REST-контроллер
Код ITЗагрузка примера кода…
Разбор:
- фрагмент показывает прикладной сценарий по теме раздела: здесь есть входные данные, операции над ними и проверяемый итог.
- аннотации
RestController,RequestMapping,GetMapping,PostMapping,ResponseStatus,RequestBodyвключают поведение фреймворка (тестовый раннер, web-маршрутизация, ORM или транзакционные правила). - ключевые вызовы
RequestMapping,NoteController,list,findAll,ResponseStatus,create,saveзадают основную механику этого примера: обработку, проверку и формирование результата. - чтение этого блока по шагам дает предсказуемую картину — сначала подготовка данных, затем действие API, затем получение конечного значения.
- после запуска стоит проверить именно эффект этого примера — вывод, значение переменной, статус ответа, состояние БД или результат теста.
- при переносе в production обычно добавляют валидацию входа, явную обработку ошибок и тест на граничные случаи вокруг этого сценария.
./mvnw spring-boot:run
Разбор:
- команды в этом фрагменте выполняются по шагам и составляют практический workflow — запуск, тесты, сборка или проверка окружения.
- последовательность
./mvnw spring-boot:runпокрывает ключевые этапы жизненного цикла проекта в CLI. - если одна команда завершается ошибкой, последующие шаги не подтверждают корректность сценария, пока не устранена первопричина.
- результат смотрят по exit code и по логам команды: успешный статус, ожидаемые артефакты и отсутствие stack trace.
- такой же набор команд обычно фиксируют в CI, чтобы локальная проверка и pipeline давали одинаковый результат.
Проверка
curl http://localhost:8080/api/notes
curl -X POST http://localhost:8080/api/notes \
-H "Content-Type: application/json" \
-d '{"text":"JPA работает"}'
Разбор:
- команды в этом фрагменте выполняются по шагам и составляют практический workflow — запуск, тесты, сборка или проверка окружения.
- последовательность
curl http://localhost:8080/api/notes,curl -X POST http://localhost:8080/api/notes \,-H "Content-Type: application/json" \,-d '{"text":"JPA работает"}'покрывает ключевые этапы жизненного цикла проекта в CLI. - если одна команда завершается ошибкой, последующие шаги не подтверждают корректность сценария, пока не устранена первопричина.
- результат смотрят по exit code и по логам команды: успешный статус, ожидаемые артефакты и отсутствие stack trace.
- такой же набор команд обычно фиксируют в CI, чтобы локальная проверка и pipeline давали одинаковый результат.
Консоль H2: http://localhost:8080/h2-console (JDBC URL из application.properties).
Ключевые понятия
| Термин | Смысл |
|---|---|
Entity | таблица в виде класса |
PersistenceContext | кэш сессии Hibernate |
ddl-auto=update | схема подстраивается (только dev!) |
Lazy loading | связи грузятся по требованию |
Production: миграции через Flyway или Liquibase, не ddl-auto=update.
Жизненный цикл сущности простыми словами
Чтобы перестать "магически" воспринимать JPA, полезно держать в голове четыре состояния объекта:
| Состояние | Что это значит |
|---|---|
| New (transient) | объект создан через new, в БД еще нет |
| Managed | объект прикреплен к persistence context, Hibernate отслеживает изменения |
| Detached | объект был managed, но контекст закрыт |
| Removed | объект помечен на удаление и будет удален при flush/commit |
Практическая выгода — вы понимаете, почему save() иногда делает INSERT, а иногда UPDATE.
Сервисный слой и транзакции
В учебном примере контроллер работает напрямую с репозиторием, это нормально для старта. В боевом сервисе обычно добавляют слой сервиса и явную транзакцию:
Код ITЗагрузка примера кода…
Разбор:
- фрагмент показывает прикладной сценарий по теме раздела: здесь есть входные данные, операции над ними и проверяемый итог.
- аннотации
Service,Transactionalвключают поведение фреймворка (тестовый раннер, web-маршрутизация, ORM или транзакционные правила). - ключевые вызовы
NoteService,rename,findById,orElseThrow,ResponseStatusException,setTextзадают основную механику этого примера: обработку, проверку и формирование результата. - чтение этого блока по шагам дает предсказуемую картину — сначала подготовка данных, затем действие API, затем получение конечного значения.
- после запуска стоит проверить именно эффект этого примера — вывод, значение переменной, статус ответа, состояние БД или результат теста.
- при переносе в production обычно добавляют валидацию входа, явную обработку ошибок и тест на граничные случаи вокруг этого сценария.
Почему так удобнее:
- бизнес-логика не размазывается по контроллерам;
- правила транзакций концентрируются в одном месте;
- код проще покрывать тестами.
Связи сущностей на минимальном примере
Частый шаг после первой таблицы — добавить автора заметки:
Код ITЗагрузка примера кода…
Разбор:
- фрагмент показывает прикладной сценарий по теме раздела: здесь есть входные данные, операции над ними и проверяемый итог.
- аннотации
Entity,Id,GeneratedValue,ManyToOne,JoinColumnвключают поведение фреймворка (тестовый раннер, web-маршрутизация, ORM или транзакционные правила). - ключевые вызовы
GeneratedValue,ManyToOne,JoinColumnзадают основную механику этого примера: обработку, проверку и формирование результата. - чтение этого блока по шагам дает предсказуемую картину — сначала подготовка данных, затем действие API, затем получение конечного значения.
- после запуска стоит проверить именно эффект этого примера — вывод, значение переменной, статус ответа, состояние БД или результат теста.
- при переносе в production обычно добавляют валидацию входа, явную обработку ошибок и тест на граничные случаи вокруг этого сценария.
На этом этапе важно понимать разницу EAGER и LAZY, иначе появляются лишние SQL-запросы и просадки производительности. Полезное продолжение: ввод-вывод и файлы и асинхронность, если API работает под нагрузкой.
Частые ошибки на старте JPA
@Entityбез пустого конструктора — Hibernate не сможет создать объект.- Использование
ddl-auto=updateв production — миграции становятся непредсказуемыми. - Возврат сущностей напрямую во внешний API без DTO — утечки полей и проблемы с lazy loading.
- Отсутствие индексов в БД на часто фильтруемые поля.
Дальше
- связи
@OneToMany,@ManyToOne; @Transactionalна сервисном слое;- JUnit 5 с
@DataJpaTest.