orm java что это
Java Hibernate
Вступление
В сегодняшней IT-индустрии хранение и извлечение данных приложений базируется на объектно-ориентированных языках программирования и реляционных базах данных. Базы данных хранят большой объем информации в одном месте. Наряду с этим, они предоставляют эффективный способ поиска записей, чтобы легко и быстро добраться до нужных данных.
Но при работе с объектами есть одна функция, которую база данных не поддерживает, — это хранение самих объектов, поскольку в ней хранятся только реляционные данные. Данные в виде объектов обеспечивают абстракцию и переносимость.
Существует ли метод, с помощью которого возможно напрямую хранить и извлекать объекты в реляционной базе данных? Ответ — да, такая возможность есть. Название этой техники — ORM.
Объектно-реляционное отображение (Object Relational Mapping, ORM)
ORM устраняет несоответствие между объектной моделью и реляционной базой данных. Само название предполагает отображение объектов в реляционные таблицы. Технология ORM преобразует объекты в реляционные данные и обратно. Возникает вопрос: как это делается?
По сути, имя переменной экземпляра присваивается имени столбца, а его значение формирует строку в реляционной базе данных. Теперь вопрос в том, нужно ли объявлять таблицу в базе данных для хранения объектов. Ответ — нет, ORM сделает это за нас, объявив типы данных для столбцов такими же, как и для переменных экземпляра.
Однако для этого нужно выполнить небольшую настройку и сообщить ORM, как будут отображаться объекты. В Java ORM работает с обычными старыми классами объектов Java (POJO), объекты которых необходимо сопоставить. Эти классы по сути состоят из частных переменных экземпляра, параметризованного конструктора с общедоступными геттерами и сеттерами.
Наряду с параметризованным конструктором класс POJO должен иметь открытый конструктор без аргументов, поскольку он необходим ORM для сериализации. Поскольку параметризованный конструктор присутствует, compile не будет добавлять конструктор аргументов самостоятельно, поэтому придется делать это вручную.
Что такое Hibernate?
Hibernate — это высокопроизводительный инструмент объектно-реляционного сопоставления с открытым исходным кодом для языка программирования Java. Он был выпущен в 2001 году Гэвином Кингом и его коллегами из Cirrus Technologies в качестве альтернативы Entity Beans (объектным бинам) в стиле EJB2.
Этот фреймворк отвечает за решение проблем несоответствия объектно-реляционного импеданса. В Java есть спецификация под названием Java Persistence API (JPA), которая описывает управление объектами в реляционной базе данных. Hibernate — это всего лишь реализация JPA.
Архитектура Hibernate
Обсудим компоненты, из которых состоит Hibernate. Hibernate имеет многоуровневую архитектуру и позволяет работать, даже не зная базовых API, реализующих объектно-реляционное сопоставление. Hibernate находится между Java-приложением и базой данных. Архитектура Hibernate подразделяется на четыре уровня:
На приведенной выше диаграмме показаны все четыре слоя. Поток данных между Java-приложением и базой данных выполняется с использованием постоянного объекта, определенного Hibernate. Уровень инфраструктуры Hibernate состоит из различных объектов, таких как конфигурация, фабрика сеансов, сеанс, транзакция, запрос и критерии. Эти объекты создаются вручную, по мере необходимости.
Объект конфигурации. Первый объект Hibernate, который должен присутствовать в любом Hibernate-приложении. Он активирует платформу Hibernate. Объект конфигурации создается только один раз во время инициализации приложения. Это родительский объект — именно из него создаются все остальные. Он проверяет, является ли файл конфигурации синтаксически правильным или нет. Он предоставляет свойства конфигурации и сопоставления, необходимые Hibernate.
Объект фабрики сеансов. Фабрика сеансов — это массивный потокобезопасный объект, используемый несколькими потоками одновременно. Таким образом, в приложении он должен быть создан только один раз и сохранен для последующего использования. Для каждой базы данных необходим отдельный объект фабрики сеансов. Фабрика сеансов отвечает за настройку Hibernate посредством свойств конфигурации, предоставляемых объектом конфигурации.
Объект сеанса. Облегченный объект, который создается каждый раз, когда нужно взаимодействовать с базой данных. Постоянные объекты сохраняются и извлекаются с помощью объекта сеанса. Это не потокобезопасный объект, поэтому его следует уничтожить после завершения взаимодействия.
Объект транзакции. Представляет собой единицу работы с базой данных. Это необязательный объект, но его следует использовать для обеспечения целостности данных и в случае возникновения какой-либо ошибки — выполнять откат.
Объект запроса. Объект запроса нужен для записи запросов и выполнения операций CRUD в базе данных. Можно написать запрос на SQL или воспользоваться языком запросов Hibernate (HQL). В процессе реализации вам станет известно о HQL больше.
Объект критериев. С его помощью выполняются объектно-ориентированные запросы для извлечения объектов из базы данных.
Как настроить Hybernate?
Во-первых, нужно установить Hibernate у себя в проекте. Можно загрузить jar-файл или воспользоваться более удобным способом, например, применить maven. Так и поступим. Загрузим зависимость hibernate, определенную в POM.xml.
Фреймворк Hibernate должен знать, как сопоставлять объекты, учетные данные сервера базы данных, где будут храниться и откуда будут извлекаться объекты, и еще несколько свойств. Вопрос в том, как передать всю эту информацию в Hibernate.
Эта настройка выполняется с помощью двух XML-файлов.
Рассмотрим пример работы с объектом Flight. В качестве переменных экземпляра он содержит идентификатор (ID), номер рейса, место отправления, место прибытия, дату рейса и тариф. Идентификатор будет первичным ключом таблицы.
Свойство hbm2ddl.auto проверяет или экспортирует язык определения данных схемы при создании объекта фабрики сеансов. Здесь мы прописали операцию обновления, которая обновит базу данных, не затрагивая ранее записанные данные. Недостает еще нескольких, таких как проверка, создание и создание-удаление.
Настало время, когда нужно создать класс POJO для рейсов ( Flights ), объекты которого будут сохраняться в таблице FLIGHTS. Здесь есть также пустой конструктор по умолчанию, необходимость которого мы обосновали ранее.
Один вопрос, который наверняка приходит вам в голову: если мы, Java-разработчики, пользуемся инструментарием Java, зачем выполнять настройку с использованием XML? Есть ли какой-нибудь другой способ? Ответ таков: да, но только частично.
Нужно просто добавить аннотации внутри класса POJO. Отдельного файла не требуется:
Аннотацию необходимо указывать непосредственно над объявлением поля.
Реализация Hibernate
Другой способ будет определен в приведенном ниже примере. Процедура создания всех остальных объектов одинакова для обоих вариантов.
Операция сохранения
Метод сохранения в объекте сеанса выполняет задачу вставки объекта.
Операция обновления
Теперь продвинемся вперед и попробуем обновить уже существующие в таблице данные.
Примечание: если вам хочется вывести объекты, извлеченные из базы данных, на консоль, добавьте метод toString() в класс POJO, иначе выведется хэш-код.
Операция удаления
После выполнения метода deleteFlight таблица становится пустой. В приведенном выше коде мы сначала извлекли объект по его идентификатору и передали его методу удаления. Если все пойдет хорошо, транзакция окажется зафиксирована, в противном случае выполнится откат.
И еще одно: хотим ли мы обновить объект в базе данных или удалить его, нам понадобится значение его первичного ключа. Однако у нас не всегда есть возможность его получить. Кроме того, для этого необходимо выполнять сложные операции с данными. Цели можно достичь с помощью HQL, аналогичного SQL, но он удаляет шаблонный код. Это означает, что теперь не нужно использовать операторы select с запросами.
Все, что мы изучили, также можно повторить, посмотрев это видео.
Руководство по Hibernate. Введение.
Что такое JDBC?
JDBC (Java Database Connectivity) – это технология, которая обеспечивает доступ Java API к реляционным базам данных. Благодаря этому, наши Java-приложения могут выполнять SQL-запросы и взаимодействовать с базами данных (далее – БД), котрые поддерживают SQL.
JDBC является крайне гибкой и позволяет нам писать приложения, которые не зависят от конкретной платформы и могут взаимодействовать с различными СУБД без каких либо изменение в программном коде.
Какие плюсы даёт нам JDBC:
Простой и понятный синтаксис
Что такое ORM (Object Relational Mapping)?
Когда мы создаём приложение на Java и хотим сделать так, чтобы наше приложение получило доступ к информации, которая хранится в БД, мы должны понимать крайне важную деталь.
Сущействует огромная разница между объектной моделью и реляционной.
СУБД даёт нам информацию в табличном формате, в то время, как Java даёт нам информацию в виде некоего графа объектов.
Класс Developer.java
И есть таблица в БД, которая также представляет разработчика:
Таблица HIBERNATE_DEVELOPER:
Допустим, что после того, как мы создали и java-класс и таблицу в БД, нам необходимо изменить нашу БД, у нас сразу же возникает проблема.
К тому же, когда мы записываем или читаем данные в/из БД, у нас есть 5 проблем, которые связаны с разницей между объекто-ориентированной (далее – ОО) моделью и реляционной моделью:
Отсюда возникает проблема: как сделать так, чтобы Java приложение получало доступ к БД и могло корректно интерпретировать эту информацию.
Другими словами, нам нужно создать связь между Объектом и реляционной сущностью, иначе говоря Объектно-Реляционное-Связывание или же – ORM (Object-Relational Mapping).
ORM – это техника программирования, которая служит для того, чтобы обеспечивать преобразование данных при их обмене между реляционной базой данных и (в нашем случае) Java.
Так какие же преимущества нам даёт ORM в сравнение с JDBC?
А самыми распрастранёнными ORM фреймворками являются:
ORM (Object-Relational Mapping, объектно-реляционное отображение) — технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования. В объектно-ориентированном программировании объекты приложения представляют объекты реального мира. ORM предназначена для преобразования объектов в форму для их сохранения в файлах или базах данных, а также их дальнейшего извлечения в программе с сохранением свойств объектов и отношений между ними. Такие объекты называют «хранимыми» (persistent). ORM освобождает программиста от работы с SQL-скриптами и позволяет сосредоточиться на ООП.
Для сохранения Java-объектов в базе данных и чтения из БД следует использовать JPA. JPA (Java Persistence API) — программный интерфейс API, входящий с версии Java 5 в состав платформ Java SE и Java EE. Существует несколько реализаций интерфейса JPA, среди которых наиболее популярным является Hibernate.
Непосредственно JPA представлен в пакете javax.persistence и включает платформо-независимый объектно-ориентированный язык запросов JPQL.
JPA оперирует таким понятием, как сущность Entity, которая является POJO-классом и связана с БД с помощью аннотации @Entity или через файл конфигурации XML. К такому классу предъявляются следующие требования :
При этом сущность может иметь непустые конструкторы, наследоваться или быть наследованной, содержать методы, не связанные со свойствами (методы get/set), и реализовывать интерфейсы. Entities могут быть связаны друг с другом (один-к-одному, один-ко-многим, многие-к-одному и многие-ко-многим).
Примеры сущностей Entity
В самом простом виде (без методов определения и получения значения свойств) JPA сущности можно представить следующим образом :
При описании сущностей были использованы аннотации. Пример использования аннотаций при описании сущности представлено здесь.
Java Persistence Query Language (JPQL) — платформо-независимый объектно-ориентированный язык запросов являющийся частью спецификации JPA.
JPQL используется для написания запросов к сущностям, хранящимся в реляционной базе данных. JPQL во многом похож на SQL, но в отличие от последнего, оперирует запросами, составленными по отношению к сущностям JPA, в отличие от прямых запросов к таблицам базы данных. В дополнение к получению объектов (запросы SELECT), JPQL поддерживает запросы, основанные на операторах UPDATE и DELETE. JPA реализует концепцию ORM.
JPQL основан на Hibernate Query Language (HQL), более раннем не стандартизованном языке запросов, включённом в библиотеку объектно-реляционного отображения Hibernate. Hibernate и HQL были созданы до появления спецификации JPA. JPQL является подмножеством языка запросов HQL.
Примеры JPQL
JPQL запрос получения списка авторов сущности «Author», упорядоченных в алфавитном порядке, имеет вид :
Запрос получения списка авторов, когда-либо опубликованных издательством «Publisher Press» :
Основы Hibernate
Хочу начать со слов благодарности тому человеку, который мне вчера накинул кармы, позволив этим писать мне в персональный блог.
Долго думал, о чем же написать свой «первый» топик… Слово первый не зря взял в кавычки, так как первый топик на самом деле уже был, опыт был к сожалению неудачный — дело закончилось баном. Решил больше не копипастить. Уверенности тому, что надо написать что-то свое, придал вот этот топик. Решил твердо — пусть это будет и редко, но буду писать сам.
Совсем недавно, по роду свой деятельности, мне пришлось столкнуться с таким понятием как ORM — (англ. Object-relational mapping). В двух словах ORM — это отображение объектов какого-либо объектно-ориентированного языка в структуры реляционных баз данных. Именно объектов, таких, какие они есть, со всеми полями, значениями, отношениями м/у друг другом.
ORM-решением для языка Java, является технология Hibernate, которая не только заботится о связи Java классов с таблицами базы данных (и типов данных Java в типы данных SQL), но также предоставляет средства для автоматического построения запросов и извлечения данных и может значительно уменьшить время разработки, которое обычно тратится на ручное написание SQL и JDBC кода. Hibernate генерирует SQL вызовы и освобождает разработчика от ручной обработки результирующего набора данных и конвертации объектов, сохраняя приложение портируемым во все SQL базы данных.
Итак, перед нами стоит задача написать небольшое приложение, которое бы осуществляло простое взаимодействие с базой данных, посредством технологии Hibernate.
Немного подумав, решил написать так называемый «Виртуальный автопарк». Суть парка такова: есть автобусы, есть маршруты и есть водители. Автобусы и маршруты связаны отношением один ко многим, т.е. на одном маршруте может кататься сразу несколько автобусов. Водители и автобусы связаны отношением многие ко многим, т.е. один водитель может водить разные автобусы и один автобус могут водить разные водители. Вроде ничего сложного.
Вот схема базы данных.
За качество не ругайте — под рукой не оказалось нормального инструмента таблички рисовать…
Вот ссылка на дамп, снятый с базы, вдруг кто-то решит все это дело поднять 🙂
Приступаем к коду. Во первых нам необходимо описать классы наших сущностей, т.е. класс автобуса, водителя и маршрута.
Класс автобус.
import java.util.Set;
import java.util.HashSet;
public class Bus <
private Long id;
private String number;
private Set drivers = new HashSet();
private Long route_id;
import java.util.Set;
import java.util.HashSet;
public class Driver <
private Long id;
private String name;
private String surname;
private int age;
private Set busses = new HashSet();
import java.util.Set;
import java.util.HashSet;
public class Route <
private Long id;
private String name;
private int number;
private Set busses = new HashSet();
Заметьте, что все классы сущностей должны соответствовать Java naming conventions, т.е. у них должны быть обязательно геттеры, сеттеры и конструктор по умолчанию. Ничего сложного 🙂
Теперь для наших классов необходимо описать маппинг в виде xml-файлов, эти файлы как раз и будут отвечать за взаимодействие наших объектов с Hibernate и с базой данных.
Bus.hbm.xml
hibernate-mapping >
class name =«logic.Bus» table =«busses» >
id column =«bus_id» name =«id» type =«java.lang.Long» >
generator class =«increment» />
id >
property column =«number» name =«number» type =«java.lang.String» />
set name =«drivers» table =«busDriver» lazy =«false» >
key column =«bus_id» />
many-to-many column =«driver_id» class =«logic.Driver» />
set >
Driver.hbm.xml
hibernate-mapping >
class name =«logic.Driver» table =«drivers» >
id column =«driver_id» name =«id» type =«java.lang.Long» >
generator class =«increment» />
id >
property column =«name» name =«name» type =«java.lang.String» />
property column =«surname» name =«surname» type =«java.lang.String» />
property column =«age» name =«age» type =«java.lang.Integer» />
set name =«busses» table =«busDriver» lazy =«false» >
key column =«driver_id» />
many-to-many column =«bus_id» class =«logic.Bus» />
set >
hibernate-mapping >
class name =«logic.Route» table =«routes» >
id column =«route_id» name =«id» type =«java.lang.Long» >
generator class =«increment» />
id >
property column =«name» name =«name» type =«java.lang.String» />
property column =«number» name =«number» type =«java.lang.Integer» />
set name =«busses» lazy =«false» >
key column =«route_id» />
one-to-many class =«logic.Bus» />
set >
Теперь создадим главный конфигурационный файл hibernate.cfg.xml, файл, откуда он будет дергать всю необходимую ему информацию.
session-factory >
property name =«connection.url» > jdbc:mysql://localhost/autopark property >
property name =«connection.driver_class» > com.mysql.jdbc.Driver property >
property name =«connection.username» > root property >
property name =«connection.password» />
property name =«connection.pool_size» > 1 property >
property name =«current_session_context_class» > thread property >
property name =«show_sql» > true property >
property name =«dialect» > org.hibernate.dialect.MySQL5Dialect property >
mapping resource =«logic/Bus.hbm.xml» />
mapping resource =«logic/Driver.hbm.xml» />
mapping resource =«logic/Route.hbm.xml» />
Тут я не буду особо вдаваться в объяснение, думаю многим и так все понятно 🙂 Скажу, что надо только в конце не забыть добавить тег mapping и указать в качестве параметра resources файлы конфигурации ваших бинов.
Теперь создадим класс, который будет хавать наш конфиг-файл и возвращать нам объект типа SessionFactory, который отвечает за создание hibernate-сессии.
import org.hibernate.cfg.Configuration;
import org.hibernate.SessionFactory;
public class HibernateUtil <
private static final SessionFactory sessionFactory;
static <
try <
sessionFactory = new Configuration().configure().buildSessionFactory();
> catch (Throwable ex) <
System.err.println( «Initial SessionFactory creation failed.» + ex);
throw new ExceptionInInitializerError(ex);
>
>
Теперь нам осталось разобраться со взаимодействием нашего приложения с базой данных. Для этого для каждого класса-сущности, определим интерфейс, содержащий набор необходимых методов (Я приведу только один интерфейс и одну его реализацию, интерфейсы и реализации для др. классов подобны этим.)
import logic.Bus;
import logic.Driver;
import logic.Route;
import java.util.Collection;
import java.sql.SQLException;
public interface BusDAO <
public void addBus(Bus bus) throws SQLException;
public void updateBus(Long bus_id, Bus bus) throws SQLException;
public Bus getBusById(Long bus_id) throws SQLException;
public Collection getAllBusses() throws SQLException;
public void deleteBus(Bus bus) throws SQLException;
public Collection getBussesByDriver(Driver driver) throws SQLException;
public Collection getBussesByRoute(Route route) throws SQLException;
Теперь определим реализацию этого интерфейса в классе BusDAOImpl
import DAO.BusDAO;
import logic.Bus;
import logic.Driver;
import logic.Route;
import java.sql.SQLException;
import java.util.Collection;
import java.util. ArrayList ;
import java.util. List ;
import util.HibernateUtil;
import javax.swing.*;
import org.hibernate.Session;
import org.hibernate.Query;
public class BusDAOImpl implements BusDAO <
Еще рас скажу, что реализации DriverDAOImpl и RouteDAOImpl будут аналогичны этой.
Наибольший интерес для нас представляют два последних метода, взгляните на них повнимательнее. Как происходит общение с базой? От объекта SessionFactory создается новая или получается текущая сессия, зачем начинается транзакция, выполняются необходимые действия, коммит транзакции и закрытие сессии. Вроде ничего сложного 🙂 Обратите внимание, на то, каким синтаксисом описан запрос к базе. Это так называемый HQL (Hibernate Query Language) HQL представляет собой объектно-ориентированный язык запросов, возможности его широки, но мной настолько широко еще не осилены 🙂 Помимо save, load, update, delete и HQL, можно пользоваться и обычным SQL. Например:
String query = «SELECT driver_id, name, surname, age FROM drivers»;
List drivers = new ArrayList();
drivers = (List) session.createSQLQuery(query).list();
Теперь создадим класс фабрики, к которой будем обращаться за нашими реализациями DAO, от которых и будем вызывать необходимые нам методы.
private static BusDAO busDAO = null ;
private static DriverDAO driverDAO = null ;
private static RouteDAO routeDAO = null ;
private static Factory instance = null ;
public static synchronized Factory getInstance() <
if (instance == null ) <
instance = new Factory();
>
return instance;
>
public BusDAO getBusDAO() <
if (busDAO == null ) <
busDAO = new BusDAOImpl();
>
return busDAO;
>
public DriverDAO getDriverDAO() <
if (driverDAO == null ) <
driverDAO = new DriverDAOImpl();
>
return driverDAO;
>
Теперь нам осталось создать какой-либо демонстрационный класс, для того, чтобы посмотреть и опробовать все то, что мы написали. Ну, не будем тянуть, вот этот класс, возможно не самый удачный, но все же 🙂
public class Main <
public static void main( String [] args) throws SQLException <
Еще раз скажу, что может не самый удачный вариант использования всего нами написанного, но для этого уже лучше GUI писать или Web-интерфейс, а это уже другая песня 🙂