1.1 Маппинг классов на таблицы
После изучения JDBC у тебя скорее всего сложилось мнение, что работать с базой данных из Java-приложения — то еще удовольствие. А что если я скажу, что всю это работу можно сделать в 10 раз проще?
В чем главное преимущество языка SQL? Это декларативный язык — он описывает, что мы хотим получить, и совсем ничего не говорит о том, как это сделать. Как — это уже забота SQL-сервера.
Тот же подход можно использовать и при работе с базами данных.
В идеальном мире мы могли бы просто писать SQL-запросы к базе, а в ответ нам бы приходили готовые Java-объекты, ну или коллекции Java-объектов, если мы запросили несколько штук.
Что сказать, именно так подумали несколько ребят в 2000 году и решили написать свой ORM framework.
ORM расшифровывается как Object-Relational Mapping и по сути является маппингом Java-объектов на SQL-запросы.
Ребята придумали очень простую вещь — каждой таблице в базе данных должен соответствовать какой-то класс в Java-приложении. В Java приложении мы оперируем объектами, а эти объекты уже умеют сами сохранять себя в базу данных.
Было три подхода к решению этой задачи, и выглядели они примерно так:
- Объект сам себя сохраняет в базу данных и обновляет свои поля на основе информации из БД.
- Объект умеет сохранять себя в базу данных, но никогда не выступает инициатором этого дела.
- Объект содержит только данные, и кто-то его сохраняет в базу данных и загружает из БД.
Изначально доминировал первый подход, тогда были популярны Application-сервера и Enterprise Java Beans. Был даже целый класс бинов, которые назывались Persistence EJB, которые умели себя сохранять в базу сами.
Но однажды все изменилось…
1.2 Появление Hibernate
В 2001 году была выпущена первая версия фреймворка Hibernate. Это был очень простой фреймворк, но он позволял использовать обычные "глупые объекты", которые ничего не знали о том, как их нужно сохранять в базу или загружать оттуда.
Маппинг полей Java-классов и колонок в таблице в базе задавался с помощью XML-файла. И иногда они были довольно громоздкими. Ладно, кого я обманываю. Это были здоровенные полотна XML-кода. И ситуацию спасало только то, что 20 лет назад не было таких гигантских баз данных, как сейчас.
Но на самом деле самым сильным решением было наконец-то отделить объект, который нужно сохранять в базу, от кода, который его туда сохранял. Это решение на самом деле неочевидное. Потому как принцип инкапсуляции утверждает, что объект лучше всех знает о том, как его нужно сохранять и загружать.
И подход ORM действительно ломает эту концепцию. Data-класс выставляет наружу свое внутреннее устройство, зато оперировать группами объектов разных типов стало значительно проще.
Серьезный прорыв случился после выхода Java 5, когда в JDK появились две вещи:
- Аннотации
- Proxy
Аннотации быстро вытеснили XML, и теперь прямо в Java-классе можно было легко указать все нужные настройки для маппинга Java-класса на таблицу в базе данных.
Прокси не так заметны для пользователя Hibernate, но их вклад был еще серьезнее. Когда ты запрашиваешь определённый объект или объекты у Hibernate, он просто возвращает тебе заглушку (proxy), и перехватывает все обращения к ее методам.
Это позволило реализовать различные механизмы Lazy Loading’а и подняло скорость и эффективность работы Hibernate на совсем заоблачный уровень для того времени. Hibernate стал не просто стандартом отрасли де-факто — его начали переводить на другие языки. Так, например для C# появился Framework NHibernate.
1.3 Появление JPA
За де-факто пришло и признание де-юре. Разработчики JDK решили создать спецификацию по тому, как правильно мапить объекты на таблицы в базе данных. Эта спецификация называется JPA — Java Persistence API.
Это именно спецификация. Она описывает, как все должно работать и какими аннотациями нужно отмечать различные части класса, если мы хотим, чтобы его объекты сохранялись в базу данных.
Такое ощущение, что ребята просто взяли за основу Hibernate и поменяли у него имена пакетов. Потому что все аннотации, которые были в Hibernate, почти один в один переехали в JPA.
На сегодняшний день Hibernate полностью реализует всю спецификацию JPA, а также некоторые дополнительные возможности, которые делают работу с ним еще комфортнее. Поэтому с точки зрения стандартизации можно сказать, что у Hibernate есть два набора функций:
- JPA-стандарт
- Hibernate Native API (дополнительная функциональность)
В официальной документации Hibernate это описывается так:
Но и на основе своего опыта, и после повторного прочтения документации по Hibernate я могу сказать, что JPA и Hibernate API совпадают на 95%. Это просто тождественные понятия.
1.4 Maven для Hibernate
Раз уж я так сильно расхвалил Hibernate, думаю, настало время перейти к работе с ним немного поплотнее.
Во-первых, есть официальный сайт, где просто куча англоязычной документации. Она, конечно, имеет уклон в справочную информацию, а не в обучающую. Но все равно лучше так, чем дебажить исходники, верно? :)
Инструкция:
- Открываешь ссылку.
- Долго на нее смотришь.
- Возвращаешься на JavaRush.
- Читаешь мои дальнейшие лекции.
Моя работа и состоит в том, чтобы упрощать сложные вещи и объяснять их простыми словами. И если ты дошел до этого уровня, значит, у меня это получается.
Ну, а чтобы приступить к работе с Hibernate, тебе нужно добавить его в свой pom.xml. На сегодняшний день доступна уже 6-я версия Hibernate, а точнее 6.1.1, так что будем учиться работать с самой последней версией.
Просто добавь в свой pom.xml такие строки:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.1.Final</version>
</dependency>
Если ты читаешь эту лекцию и за окном 2023+ год, тогда новую версию можно скачать тут.
Важно! Некоторые библиотеки, которые использует Hibernate, были исключены из JDK 11 и JDK 17, поэтому если у тебя возникают проблемы с запуском проекта, то добавь в него такие зависимости:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.0-GA</version>
</dependency>
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ