JavaRush /Курсы /Модуль 4. Работа с БД /Проект по теме: Hibernate #1

Проект по теме: Hibernate #1

Модуль 4. Работа с БД
11 уровень , 5 лекция
Открыта

Помните проект из третьего модуля по фронтенду, где нужно было реализовать админку для rpg для серверного API? Если кто помнит – там на сервере в качестве хранилища использовалась мапа. Естественно, в реальной жизни такие хранилища не используют, а используют базы данных. Целью этого проекта будет написать альтернативную реализацию слоя репозитория с использованием Hibernate.

Для этого нужно:

  1. Сделать fork из репозитория
  2. Скачать свою версию проекта к себе на компьютер.
  3. Добавить зависимости в pom.xml:
    • mysql: mysql-connector-java: 8.0.30
    • org.hibernate: hibernate-core-jakarta: 5.6.11.Final
  4. Сделать maven билд (mvn clean install). Для разнообразия используем Java версии 1.8.
  5. Добавить конфигурацию запуска через Идею. Реализацию этого пункта можно посмотреть в лекции https://javarush.com/quests/lectures/jru.module3.lecture02 (пункт 4). Единственное отличие – другое название артефакта. Если все сделал правильно и запустил приложение – увидишь примерно такую картину:
  6. В Workbench выполнить скрипт создания схемы rpg:
    CREATE SCHEMA `rpg` ;
    
  7. Опционально. Если хочешь посмотреть какое ожидается поведение, можешь в классе com.game.service.PlayerService в параметре конструктора значение аннотации @Qualifier изменить с «db» на «memory». В этом случае Spring будет использовать в качестве реализации интерфейса IPlayerRepository класс PlayerRepositoryMemory. После теста не забудь изменить значение аннотации @Qualifier обратно на «db».
  8. Расставить все необходимые аннотации в ентити-классе com.game.entity.Player. Таблица должна называться «player», схема «rpg». Для енамов используй @Enumerated(EnumType.ORDINAL) кроме аннотации @Column. Напомню, что длина поля name должна быть до 12 символов, поля title – до 30 символов. Абсолютно все поля не должны быть null.
  9. В классе PlayerRepositoryDB добавь private final поле SessionFactory sessionFactory, в конструкторе класса инициализируй это поле. Проперти используй как в обычных задачах (работать будем с БД MySQL версии 8). Из интересного – добавь
    properties.put(Environment.HBM2DDL_AUTO, "update");
    
    Это позволит не создавать таблицу вручную (или через выполнения sql скрипта).
  10. Реализуй все методы класса. Для разнообразия давай поступим так:
    • Метод getAll реализуй через NativeQuery — этот метод должен получать всех игроков  с учетов параметров: pageNumber - номер страницы, pageSize - количество записей на страницу
    • Метод getAllCount реализуй через NamedQuery. Должен возвращать общее количество игроков в базе данных.
    • В методе beforeStop вызови у sessionFactory метод close. За счет наличия аннотации над методом @PreDestroy, Spring вызовет этот метод перед остановкой приложения, и это позволит валидно освободить все ресурсы системы.
    • Реализация остальных методов на твое усмотрение. Но не забывай о транзакциях и коммитах для методов, которые как либо изменяют содержимое БД.
  11. Запусти приложение. Если все сделал правильно – ты получишь рабочее приложение. Вот только данных там никаких нет, так что выполни через Workbench скрипт init.sql (из ресурсов), чтоб они появились. После этого в браузере нажми F5 и проверяй, что все методы ты реализовал правильно.
  12. Было бы интересно посмотреть, какие именно запросы выполняет Hibernate, поэтому добавим логирование запросов. Для этого добавь в pom.xml зависимость p6spy:p6spy:3.9.1. В папке ресурсов создай файл spy.properties, в котором укажи:
    driverlist=com.mysql.cj.jdbc.Driver
    dateformat=yyyy-MM-dd hh:mm:ss a
    appender=com.p6spy.engine.spy.appender.StdoutLogger
    logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat
    
    И в конструкторе класса PlayerRepositoryDB измени две опции:
    properties.put(Environment.DRIVER, "com.p6spy.engine.spy.P6SpyDriver");
    properties.put(Environment.URL, "jdbc:p6spy:mysql://localhost:3306/rpg");
    
    Теперь в выводе сервера по каждому запросу ты будешь видеть 2 строки. Первая – какой стейтмент подготовлен, второй – запрос с вставленными параметрами.

Вот и все, проект готов, поздравляю тебя!

На самом деле, для работы с Hibernate из Spring используется другой подход, о котором мы расскажем в пятом модуле.


Разбор проекта.
Комментарии (6)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Mukhan Gazirsharif Уровень 109
12 января 2025
Hibernate отправлял в БД запрос на создание таблицы, но она упорно не создавалась. Очень долго сидел не находя ошибку. В консоли ошибок не было. Я изначально делал в Community Edition с Smart Tomcat, все работало даже Spring, потом открыл через Ultimate и Local Tomcat но не помогало. Исправил через добавление в pom.xml

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core-jakarta -->
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-core-jakarta</artifactId>
	<version>5.6.11.Final</version>
</dependency>
Может это из-за того что все поменялось на jakarta.persistence.* или из за того что я не делал "mvn clean install" через терминал, а делал его через саму IDEA через боковую панель. Еще возможно дело было в спринге, я надеялся на него что он сам все сделает.
Мария Ким Уровень 90 Expert
4 июня 2024
да, конечно, ради разнообразия будем использовать java 1.8...Почему бы ради разнообразия не использовать 17 java?
Павел Уровень 111 Expert
20 декабря 2023
После выполнения пункта 9 программа не запускается:

The web application [rpg_hibernate_war_exploded] registered the JDBC driver [com.mysql.cj.jdbc.Driver]
but failed to unregister it when the web application was stopped.
To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
Испробовал все найденные варианты решения, ничего не помогло: - редактирования файла Tomcat server.xml - перенос драйверов jdbc в папку сервера - написание класса запуска/остановки драйвера внутри приложения У кого было и как справились?
Данила Уровень 111 Expert
5 января 2024
У меня тоже, но только после 10 ничего не работает
Anonymous #3322801 Уровень 1 Expert
23 ноября 2023
И все таки в классе Player надо было делать @GeneratedValue(strategy = GenerationType.IDENTITY) оказывается
Anonymous #3322801 Уровень 1 Expert
21 ноября 2023
Из разбора сделала вывод что данные, которые мы вносим самостоятельно hiber не видит, поэтому можно сразу сделать такой код, чтобы добавление в таблицу происходило корректно:

 @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "player_seq")
    @SequenceGenerator(name = "player_seq", sequenceName = "player_seq", initialValue = 41, allocationSize=1)
    @Column(nullable = false)
    private Long id;