- Вспомогательные методы
- Постоянные сущности
- Загрузка объектов
- Отделение сущностей
- Слияние сущностей
- Запросы для сущностей
- Удаление сущностей
- Persistс
- Saveс
- Mergeс
- Updateс
- SaveOrUpdateс
- Библиотеки и стандарты
- Что такое каскадность? Как она используется в Hibernate?
- Может ли Entity класс быть абстрактным?
- String
- Какие есть способы создания объекта String? Где он создаётся?
- Как сравнить две строки в Java и как их отсортировать?
- Приведите алгоритм перевода строки в символ. Напишите соответствующий код
- Как перевести строку в массив байтов и назад ? Напишите соответствующий код
- Нюансы работы метода persist()
- Все дело в контексте сохранения
- Управляемая организация
- Как это работает?
- Transient
- Возможные варианты статуса объекта
- Обзор
- Отдельная сущность
- Поле идентичности — это все, что имеет значение
- Persistent or Managed
- Removed
- Удаленный объект
- Detached
- Нюансы работы метода save()
- Временная сущность
- Список состояний
- Заключение
Вспомогательные методы
В этом руководстве мы будем последовательно использовать несколько вспомогательных методов:
Все вышеперечисленные вспомогательные методы статически импортированы для лучшей читаемости. Вы можете найти их реализации в проекте GitHub, ссылки на которые приведены в конце этой статьи.
APIEntityManager предоставляет набор методов. Мы можем взаимодействовать с базой данных, используя эти методы.
Постоянные сущности
Чтобы иметь объект, связанный с EntityManager, мы можем использовать методpersist():
После сохранения объекта в базе данных он находится в состоянииpersistent.
Загрузка объектов
Для получения объекта из базы данных мы можем использовать методfind().
Здесь метод выполняет поиск по первичному ключу. Фактически, метод ожидает тип класса сущности и первичный ключ:
However, if we just need the reference to the entity, we can use the getReference() вместо этого. По сути, он возвращает прокси для сущности:
Movie movieRef = em.getReference(Movie.class, new Long(movieId));
Отделение сущностей
В случае, если нам нужно отсоединить объект от контекста постоянства,we can use the detach() method. Мы передаем объект, который будет отсоединен, в качестве параметра методу:
Как только объект отсоединен от контекста постоянства, он будет в отключенном состоянии.
Слияние сущностей
На практике многие приложения требуют модификации сущности для нескольких транзакций. Например, мы можем захотеть получить сущность в одной транзакции для рендеринга в пользовательский интерфейс. Затем другая транзакция внесет изменения, сделанные в пользовательском интерфейсе.
В таких ситуациях мы можем использовать методmerge(). The merge method helps to bring in the modifications made to the detached entity, in the managed entity, if any:
Запросы для сущностей
Кроме того, мы можем использовать JPQL для запроса сущностей. Мы вызовемgetResultList() для их выполнения.
Конечно, мы можем использоватьgetSingleResult(),, если запрос возвращает только один объект:
Удаление сущностей
Дополнительноwe can remove an entity from the database using the remove() method. Важно отметить, что объект не отсоединяется, а удаляется.
Здесь состояние объекта меняется с постоянного на новое:
С самого начала важно понимать, что все методы (persist,save,update,merge,saveOrUpdate) не сразу приводят к соответствующие операторы SQLUPDATE илиINSERT. Фактическое сохранение данных в базе данных происходит при фиксации транзакции или сбросеSession.
Упомянутые методы в основном управляют состоянием экземпляров сущностей, переводя их между различными состояниями на протяжении жизненного цикла.
В качестве примера сущности мы будем использовать простую сущность с отображением аннотацииPerson:
Persistс
Методpersist предназначен для добавления нового экземпляра сущности в контекст персистентности, т.е. переход экземпляра из переходного состояния в состояниеpersistent.
Мы обычно вызываем его, когда хотим добавить запись в базу данных (сохранить экземпляр сущности):
Person person = new Person();
person.setName(«John»);
session.persist(person);
Что происходит после вызова методаpersist? Объектperson перешел из состоянияtransient в состояниеpersistent. Объект находится в контексте постоянства сейчас, но еще не сохранен в базе данных. Генерация операторовINSERT будет происходить только после фиксации транзакции, сброса или закрытия сеанса.
Обратите внимание, что методpersist имеет возвращаемый типvoid. Он воздействует на переданный объект «на месте», изменяя его состояние. Переменнаяperson ссылается на фактический постоянный объект.
Этот метод является более поздним дополнением к интерфейсу сеанса. Основной отличительной чертой этого метода является то, что он соответствует спецификации JSR-220 (постоянство EJB). Семантика этого метода строго определена в спецификации, которая в основном гласит, что:
Обратите внимание, что здесь нет ничего, что касается идентификатора экземпляра. В спецификации не указано, что идентификатор будет сгенерирован сразу, независимо от стратегии генерации идентификатора. Спецификация методаpersist позволяет реализации выдавать операторы для генерации идентификатора при фиксации или сбросе, и не гарантируется, что идентификатор будет ненулевым после вызова этого метода, поэтому вам не следует полагаться на него.
Вы можете вызвать этот метод на уже существующем экземпляреpersistent, и ничего не произойдет. Но если вы попытаетесь сохранить экземплярdetached, реализация обязательно вызовет исключение. В следующем примере мыpersist сущность,evict ее из контекста, чтобы она сталаdetached, а затем снова пытаемсяpersist. Второй вызовsession.persist() вызывает исключение, поэтому следующий код работать не будет:
Person person = new Person();
person.setName(«John»);
session.persist(person);
session.evict(person);
session.persist(person); // PersistenceException!
Saveс
Методsave — это «оригинальный» метод Hibernate, который не соответствует спецификации JPA.
Его цель в основном такая же, как уpersist, но у него другие детали реализации. В документации этого метода строго говорится, что он сохраняет экземпляр, «сначала назначая сгенерированный идентификатор». Гарантируется, что метод вернет значениеSerializable этого идентификатора.
Person person = new Person();
person.setName(«John»);
Long id = (Long) session.save(person);
Эффект от сохранения уже сохраненного экземпляра такой же, как сpersist. Разница возникает, когда вы пытаетесь сохранить экземплярdetached:
Person person = new Person();
person.setName(«John»);
Long id1 = (Long) session.save(person);
session.evict(person);
Long id2 = (Long) session.save(person);
Переменнаяid2 будет отличаться отid1. Вызов save для экземпляраdetached создает новый экземплярpersistent и присваивает ему новый идентификатор, что приводит к дублированию записи в базе данных при фиксации или сбросе.
Mergeс
Основное назначение методаmerge — обновить экземпляр объектаpersistent новыми значениями полей из экземпляра объектаdetached.
Например, предположим, что у вас есть интерфейс RESTful с методом для получения сериализованного JSON-объекта по его идентификатору вызывающей стороне и методом, который получает обновленную версию этого объекта от вызывающей стороны. Сущность, прошедшая такую сериализацию / десериализацию, появится в состоянииdetached.
После десериализации этого экземпляра сущности вам необходимо получить экземпляр сущностиpersistent из контекста постоянства и обновить его поля новыми значениями из этого экземпляраdetached. Таким образом, методmerge делает именно это:
В следующем примере мыevict (отсоединяем) сохраненную сущность от контекста, меняем полеname, а затемmerge сущностьdetached.
Person person = new Person();
person.setName(«John»);
session.save(person);
session.evict(person);
person.setName(«Mary»);
Person mergedPerson = (Person) session.merge(person);
Обратите внимание, что методmerge возвращает объект — это объектmergedPerson, который был загружен в контекст сохранения и обновлен, а не объектperson, который вы передали в качестве аргумента. Это два разных объекта, и от объектаperson обычно нужно отказаться (в любом случае, не рассчитывайте, что он будет прикреплен к контексту сохранения).
Как и в случае с методомpersist, методmerge указан в JSR-220, чтобы иметь определенную семантику, на которую вы можете положиться:
Updateс
Как иpersist иsave, методupdate — это «оригинальный» метод Hibernate, который присутствовал задолго до добавления методаmerge. Его семантика отличается в нескольких ключевых моментах:
В следующем примере мыsave объект, затемevict (отсоединяем) его от контекста, затем меняем егоname и вызываемupdate. Обратите внимание, что мы не помещаем результат операцииupdate в отдельную переменную, потому чтоupdate имеет место в самом объектеperson. По сути, мы повторно подключаем существующий экземпляр сущности к контексту постоянства — что не позволяет нам делать спецификация JPA.
Person person = new Person();
person.setName(«John»);
session.save(person);
session.evict(person);
person.setName(«Mary»);
session.update(person);
Попытка вызватьupdate в экземпляреtransient приведет к исключению. Следующее не будет работать:
Person person = new Person();
person.setName(«John»);
session.update(person); // PersistenceException!
SaveOrUpdateс
Этот метод появляется только в Hibernate API и не имеет своего стандартного аналога. Подобноupdate, он также может использоваться для повторного подключения экземпляров.
Фактически, внутренний классDefaultUpdateEventListener, который обрабатывает методupdate, является подклассомDefaultSaveOrUpdateListener, просто переопределяя некоторые функции. Основное отличие методаsaveOrUpdate заключается в том, что он не генерирует исключение при применении к экземпляруtransient; вместо этого он делает этот экземплярtransientpersistent. Следующий код сохранит вновь созданный экземплярPerson:
Person person = new Person();
person.setName(«John»);
session.saveOrUpdate(person);
Вы можете рассматривать этот метод как универсальный инструмент для создания объектаpersistent независимо от его состояния, будь тоtransient илиdetached.
Hello, World!
Не переставать развиваться очень важно для любого разработчика. Ведь если остановиться, есть риск стать невостребованным и вовсе вылететь с рынка: IT мир постоянно развивается и двигается вперед, и нужно двигаться вместе с ним.
Но и при этом нельзя только зацикливаться только на новых и свежих технологиях, чтобы не забывать, так сказать, о классике (классических темах). Сегодня я хочу продолжить, свой разбор вопросов по “классическим” темам для Java-разработчика.

Отмечу, что мои ответы не являются последней инстанцией — это всего лишь то, как я вижу правильные ответы на данные вопросы, и с чем-то вы можете быть не согласны. Это будет вполне нормально, так что не стесняйтесь делиться своим мнением в комментариях.
Ссылки на части разбора — в конце статьи.

Библиотеки и стандарты
Я думаю, чтобы ответить на данный вопрос, нам сперва нужно понять, что такое JPA.
— это спецификация, описывающая объектно-реляционное отображение простых Java объектов и предоставляющая API для сохранения, получения и управления такими объектами.
То есть, как мы помним, реляционные базы данных (БД) представлены в виде множества связанных между собой таблиц. И — общепринятый стандарт, который описывает, как объекты могут взаимодействовать с реляционными базами данных.
Как видите, — это что-то абстрактное и неосязаемое. Это как бы сама идея, подход.

В то же время — это конкретная библиотека, реализующая парадигмы . То, есть с помощью этой библиотеки вы можете работать с реляционной базой данных через объекты, которые представляют данные с БД (Entity).
Как говорят, данная библиотека очень близка к идеалам и возможно, поэтому она стала популярна. А как вы понимаете, популярность использования — хороший аргумент для дальнешйей разработки и улучшений.
К тому же за частым использованием стоит огромное комьюнити, которое разобрало уже все возможные и невозможные вопросы, связанные с данным инструментом.
Вот пример книги, которая подробно разбирает все темные закоулки данной технологии. То есть, Hibernate максимально изучен и, получается, надежен.
Собственно, не зря даже идеальная реализация JPA со стороны Spring-а под капотом как правило использует Hibernate.
Что такое каскадность? Как она используется в Hibernate?
В есть понятие персистентная (persistence) сущность — сущность, связанная с её данными в БД, которая управляется текущей сессией (соединением). Если её изменить, но при этом не сохранить изменения в БД, всё равно её данные в БД будут изменены.

Hibernate поддерживает все эти стандартные каскадные операции, но также привносит три свои:
Если не выбран тип каскадирования, никакая операция с сущностью не будет иметь эффекта для связанных с ней других entity.
Может ли Entity класс быть абстрактным?
В я о таком классе не слышал, поэтому предположу, что тут имеется ввиду класс библиотеки, которая используется для модульного тестирования кода.
Класс данной библиотеки, , используется для проверки результатов выполнения кода ( — утверждение, что в определенном месте у вас определенное состояние/данные).
Например, вы тестируете метод, который должен создавать кота. Вы запускаете метод и получаете некоторый результат:
Cat resultOfTest = createCat();
Но ведь вам нужно убедиться, что он был правильно создан, не так ли?
Поэтому вы до этого создали некого кота — — вручную с точно такими параметрами, которые вы ожидаете от кота, полученного с метода .
Далее вы и используете класс для сверки полученных результатов:
Если коты будут отличаться, будет выброшено исключение , которое говорит нам о том, что ожидаемые результаты не сходятся.
У класса есть множество различных методов, которые покрывают множество задач по проверке ожидаемых результатов. Вот некоторые из них:
String
— стандартный класс в Java, отвечающий за хранение и манипуляции со строковыми значениями (последовательности символов), является классом (об я писал ранее), т.е. данные объектов данного класса невозможно изменить после создания.
Хотелось бы сразу отметить, что классы и — это два фактически одинаковых класса с той лишь разницей, что один из них предназначен для использования в многопоточной среде (StringBuffer).
Эти классы являются аналогами , но в отличие от него они .
То есть объекты после создания допускают модификацию строки, которую представляют, без создания нового объекта.
Собственно, методы отличаются от стандартных методов и направлены на удовлетворение потребностей по изменению строки (не зря же builder-ом назвали).
Подробнее о , и читайте вот в этой статье.
Какие есть способы создания объекта String? Где он создаётся?
Самый привычный способ создания строки — простое задание нужного нам значения в двойных скобках:
String str = «Hello World!»;
Также можно сделать это непосредственно через :
String str = new String(«Hello World!»);
Можно создать строку и отталкиваясь от массива символов:
Как результат работы метода на некотором объекте:
String str = someObject.toString();
Как результат работы любого другого метода возвращает строковое представление. Например:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = reader.readLine();
Как вы поняли, способов создания строки может быть очень и очень много.
При создании объекта он сохраняется в , о котором подробнее мы поговорим в одном из вопросов далее.
Как сравнить две строки в Java и как их отсортировать?
Для сравнения значений в Java используется знак двойного равно .
Если бы нам нужно было сравнивать некоторые простые значения вроде , мы бы воспользовались им.
Но для сравнения полноценных объектов данный способ неприменим. В таком случае это будет лишь сравнение ссылок — указывают ли они на один и тот же они объект или нет. То есть при сравнении двух объектов с совершенно одинаковыми значениями внутренних полей сравнение через даст результат : несмотря на одинаковость полей объектов, сами объекты занимают разные ячейки памяти.
А объекты класса , несмотря на обманчивую простоту, всё же являются объектами. И сравнение через для них также неприменимо (даже несмотря на наличие строкового пула).
Тут за дело берется стандартный метод класса — , который необходимо переопределить в классе для его корректной работы (иначе по умолчанию он сравнивает через ).
В классе он переопределен, значит просто берем и используем его:
String firstStr = «Hello World!»;
String secondStr = «Hello World!»;
boolean isEquals = firstStr.equals(secondStr);

Мы говорили о сравнении на соответствие, а теперь разберем сравнение для сортировки. Ведь для сортировки чего-либо нам нужно знать, по какому принципу сортировать. Для этого можно воспользоваться стандартным отсортированным множеством — .
Подробнее о различных коллекциях в Java вы можете почитать в этой статье.
Данный список работает на основе алгоритма красно-черного дерева и сортирует множество в соответствии с заданным принципом сортировки.
Как я и сказал ранее, нужно понимать, как отсортировать объекты определенного типа. Чтобы задать способ сравнения для сортировки, используют компараторы.
Как правило их необходимо реализовывать для классов, которые вы хотите сортировать, но в случае со они уже реализованы.
Поэтому просто добавляем нужные нам строки в , а он их отсортирует:
Вывод в консоли:
Приведите алгоритм перевода строки в символ. Напишите соответствующий код
Как я и говорил ранее, у объектов класса очень много разных полезных методов. Один из таких — . Данный метод переводит строку в массив символов:
Далее у нас есть массив символов, которые можем вызывать по индексу:
Как перевести строку в массив байтов и назад ? Напишите соответствующий код
Аналогичный методу , класс имеет метод , который возвращает массив байтов строки:
Сегодняшняя часть разбора подошла к логическому концу. Спасибо за внимание!

Нюансы работы метода persist()
При сохранении объекта в базу данных тебе нужно помнить две вещи.
Во-первых, сохранение объекта в итоге приведет к выполнению одной из команд SQL: INSERT или UPDATE. Во-вторых, эти действия произойдут не сразу после вызова метода объекта session, а только после закрытия транзакции.
Давай сохраним в базу его объект с помощью метода .
Задача этого метода сохранить в базу данных новый объект. Если такого объекта еще нет, то он будет добавлен в базу через вызов SQL-метода INSERT.
Если же объект уже есть в базе, то ничего не произойдет. Однако возможет еще и третий случай – попытка сохранить в базу объект со статусом Detached. В этом случае кинется исключение. Пример:
Все дело в контексте сохранения
Simply put, the persistence context sits between client code and data store. Это промежуточная область, где постоянные данные преобразуются в объекты, готовые к чтению и изменению клиентским кодом.
Теоретическиpersistence context является реализацией шаблонаUnit of Work. Он отслеживает все загруженные данные, отслеживает изменения этих данных и в конечном итоге отвечает за синхронизацию любых изменений обратно в базу данных в конце бизнес-транзакции.
JPAEntityManager и HibernateSession являются реализацией концепцииpersistence context В этой статье мы будем использовать HibernateSession для представленияpersistence context.
Состояние жизненного цикла объекта Hibernate объясняет, как объект связан сpersistence context, как мы увидим дальше.
Управляемая организация
A managed entity is a representation of a database table row (хотя эта строка еще не должна существовать в базе данных).
Это управляется текущими запущеннымиSession иevery change made on it will be tracked and propagated to the database automatically.
Session либо загружает объект из базы данных, либо повторно подключает отсоединенный объект. Мы обсудим отдельные объекты в разделе 5.
Давайте рассмотрим код, чтобы прояснить ситуацию.
Наш пример приложения определяет одну сущность, классFootballPlayer. При запуске мы инициализируем хранилище данных некоторыми примерами данных:
Предположим, мы хотим изменить имя Буффона для начала — мы хотим указать его полное имяGianluigi Buffon вместо Джиджи Буффон.
Во-первых, нам нужно начать нашу единицу работы с полученияSession:
Session session = sessionFactory.openSession();
В серверной среде мы можем внедритьSession в наш код через контекстно-зависимый прокси. Принцип остается тем же: нам нуженSession to, инкапсулирующий бизнес-транзакцию нашей единицы работы.
Затем мы проинструктируем нашSession загрузить данные из постоянного хранилища:
assertThat(getManagedEntities(session)).isEmpty();
List players = s.createQuery(«from FootballPlayer»).getResultList();
assertThat(getManagedEntities(session)).size().isEqualTo
;
Когда мы впервые получаемSession, его постоянное хранилище контекста пусто, как показывает наш первый операторassert.
Затем мы выполняем запрос, который извлекает данные из базы данных, создает представление данных в виде сущности и, наконец, возвращает сущность, которую мы можем использовать.
ВнутриSession keeps отслеживает все сущности, которые он загружает в постоянное хранилище контекста. В нашем случае синтернальное хранилищеSession’s будет содержать 3 сущности после запроса.
Теперь давайте изменим имя Джиджи:
Как это работает?
При вызове транзакцииcommit() илиflush(),Session найдет любые объектыdirty из своего списка отслеживания и синхронизирует состояние с базой данных.
Обратите внимание, что нам не нужно было вызывать какой-либо метод для уведомленияSession о том, что мы что-то изменили в нашей сущности — поскольку это управляемая сущность, все изменения автоматически переносятся в базу данных.
Управляемый объект всегда является постоянным объектом — он должен иметь идентификатор базы данных, даже если представление строки базы данных еще не создано, т.е. оператор INSERT ожидает окончания единицы работы.
Смотрите главу о переходных объектах ниже.
Transient
На самом деле все значительно проще чем кажется, хотя и не без нюансов. Например, каждый Entity объект, который ты создал явно с помощью Java-кода, а не загрузил из базы с помощью Hibernate, имеет статус Transient (прозрачный).
EmployeeEntity employee = new EmployeeEntity();
Статус Transient значит, что Hibernate понятия не имеет об этом объекте, и никакие действия с объектом не влияют на Hibernate, как и работа Hibernate на этот объект.
Такие объекты еще называются POJO – Plain Old Java Object. Этот термин часто используется как противоположность различным объектам с хитрым поведением. Вот помните Moc-объекты, которые создавал Mockito? Вот они не POJO.
Если некий клиентский код работает с объектом со статусом Transient, то их взаимодействие можно описать супер-простой схемой:
Возможные варианты статуса объекта
Как ты уже наверное обратил внимание, когда объект присоединен к Hibernate, его состояние называется Persistent или Managed. Как правильно? Persist или Managed?
Можно и так, и так. Согласно спецификации JPA объект имеет статус Persist, а согласно спецификации Hibernate его состояние называется Managed.
В Hibernate работа с базой ведется через объект типа org.hibernate. Session. Согласно же JPA класс должен называться javax.persistence. EntityManager. На самом деле большой проблемы тут нет, так как оба типа являются интерфейсами.
Интерфейс объявлен так:
Поэтому в интерфейсе есть все методы, которые есть в интерфейсе . Но также есть и свои, которые достались ему от более ранних версий Hibernate, когда еще не было спецификации JPA.
Описывается эта вся ситуация вот такой картинкой:

Давай же разберем все методы, которые есть у интерфейса session, а также нюансы их работы.
Обзор
У каждой сущности Hibernate естественным образом есть жизненный цикл в рамках — он находится в переходном, управляемом, отсоединенном или удаленном состоянии.
Понимание этих состояний как на концептуальном, так и на техническом уровне важно для правильного использования Hibernate.
Чтобы узнать о различных методах Hibernate, которые работают с сущностями, взгляните наone of our previous tutorials.
Отдельная сущность
A detached entity is just an ordinary entity POJO, значение идентификатора которого соответствует строке базы данных. Отличие от управляемого объекта в том, что этоnot tracked anymore by any persistence context.
Сущность может быть отсоединена, когдаSession, использованный для ее загрузки, был закрыт, или когда мы вызываемSession.evict(entity) илиSession.clear().
Посмотрим на код:
FootballPlayer cr7 = session.get(FootballPlayer.class, 1L);
assertThat(getManagedEntities(session)).size().isEqualTo
;
assertThat(getManagedEntities(session).get(0).getId()).isEqualTo(cr7.getId());
session.evict(cr7);
assertThat(getManagedEntities(session)).size().isEqualTo(0);
Наш контекст постоянства не будет отслеживать изменения в отдельных объектах:
Session.merge(entity)/Session.update(entity) can (повторно) присоединить сеанс:
FootballPlayer messi = session.get(FootballPlayer.class, 2L);
session.evict(messi);
messi.setName(«Leo Messi»);
transaction.commit();
assertThat(getDirtyEntities()).isEmpty();
transaction = startTransaction(session);
session.update(messi);
transaction.commit();
assertThat(getDirtyEntities()).size().isEqualTo
;
assertThat(getDirtyEntities().get(0).getName()).isEqualTo(«Leo Messi»);
Для справки поSession.merge() иSession.update() см.here.
Поле идентичности — это все, что имеет значение
Давайте посмотрим на следующую логику:
FootballPlayer gigi = new FootballPlayer();
gigi.setId
;
gigi.setName(«Gigi the Legend»);
session.update(gigi);
В приведенном выше примере мы создали экземпляр объекта обычным способом с помощью его конструктора. Мы заполнили поля значениями и установили для идентификатора значение 3, что соответствует идентификатору постоянных данных, принадлежащих Джиджи Буффон. Вызовupdate() имеет точно такой же эффект, как если бы мы загрузили объект из другогоpersistence context.
Фактически,Session не различает, откуда произошла повторно присоединенная сущность.
В веб-приложениях довольно распространен сценарий создания отдельных сущностей из значений HTML-формы.
Что касаетсяSession, отсоединенный объект — это просто объект, значение идентификатора которого соответствует постоянным данным.
Имейте в виду, что приведенный выше пример просто служит демонстрационной цели. и нам нужно точно знать, что мы делаем. В противном случае мы могли бы получить нулевые значения в нашей сущности, если бы мы просто установили значение в поле, которое мы хотим обновить, оставив остальное нетронутым (то есть фактически пустым).
Persistent or Managed
Следующий самый распространенный случай – это объекты, связанные с движком Hibernate. Их статус называют Persistent (или же Managed). Способов получить объект с таким статусом ровно два:
Employee employee = session.load(Employee.class, 1);
Employee employee = new Employee ();
session.save(employee);
Такому объекту обычно соответствует какая-то запись в базе данных, у него есть ID и тому подобное. Этот объект присоединен к сессии Hibernate’а, и вообще может быть представлен не реальным объектом, а неким proxy.
Вполне реальна ситуация, когда после вызова метода , тебе вернут некий объект-заглушку (proxy), и все обращения к базе данных будут выполняться только после вызова методов этого объекта. Но о таких деталях мы поговорим немного позднее.
А взаимодействие клиентского кода и объекта в статусе Managed можно описать вот такой картинкой:

Removed
И последнее состояние, которое может быть у твоего Entity-объекта – это Removed. Как ты уже наверное догадался из его названия – это состояние удаленного объекта.
Такое состояние появляется по причине того, что если ты удалишь какой-то объект из базы, то Java-объект сразу никуда не исчезнет.
Employee employee = session.load(Employee.class, 1);
//после загрузки у объекта состояние Persisted
session.remove(employee);
//после удаления у объекта состояние Removed
session.save(employee);
//а теперь снова Persisted
session.close();
//а теперь состояние Detached
Удаленный объект
ВызванAn entity is in a deleted (removed) state if Session.delete(entity), иSession has пометили объект для удаления. Сама команда DELETE может быть введена в конце единицы работы.
Давайте посмотрим на это в следующем коде:
Однако обратите внимание, что объект остается в постоянном хранилище контекста до конца единицы работы.
Detached
Следующее состояние – это когда объект был отсоединен от сессии. То есть когда-то объект был присоединен к сессии Hibernate, но затем сессия закрылась или транзакция завершилась, и Hibernate больше не следит за этим объектом.
В первом примере сессия была закрыта. Во втором случае мы явно указали, что хотим отсоединить объект от сессии с помощью метода .
Новая схема взаимодействия кода и объекта будет выглядеть так:

И вот тут будет самое интересное. Если твой объект был получен из Hibernate, то велика вероятность, что тебе отдали некий proxy вместо реального объекта. И этот proxy-объект после отсоединения от сессии будет кидать исключения при вызове его методов.
Это самая частая проблема у всех новичков при работе с Hibernate. Тебе нужно точно знать в каждый момент времени ответ на такие вопросы, когда ты работаешь с Entity-объектом:
Хорошая новость – в большинстве случаев все очевидно. Но тебе все равно нужно понимать, как это все работает под капотом. Декларативное программирование оно такое – написать код можно за 10 минут, понять почему он не работает, как надо – за 10 часов 🙂
Нюансы работы метода save()
Метод save() достался нынешнему Hibernate от его предыдущих версий. По своей сути он очень похож на метод , он тоже добавляет новую запись в таблицу с помощью метода INSERT. Однако у него есть несколько интересных нюансов.
Во-первых, этот метод возвращает значение – новое ID объекта. Как ты уже знаешь, обычно до добавления в базу у объектов нет ID и оно присваивается уже базой данных. Так вот, метод объекта session возвращает ID, которая была присвоена сохраняемому объекту.
Важно! Согласно спецификации Hibernate ID может быть любой сериализуемый объект, не только число. Это может быть строка, число, enum, вообще что угодно, что можно целиком положить в одну колонку таблицы в базе.
Метод имеет тип результата Serialized, поэтому его результат нужно приводить к правильному типу:
Также у метода другое поведение в случае с Detached состоянием объекта. Такой объект он рассматривает как новый и просто добавляет еще одну запись:
Переменные id и id2 будут отличаться. В таблице в базе данных будут добавлены две записи: по одной для каждой операции .
Временная сущность
A transient entity is simply an entity object that has no representation in the persistent store и не управляется никакимSession.
Типичным примером временного объекта может быть создание нового объекта через его конструктор.
Чтобы создать временный объектpersistent, нам нужно вызватьSession.save(entity) orSession.saveOrUpdate(entity):
FootballPlayer neymar = new FootballPlayer();
neymar.setName(«Neymar»);
session.save(neymar);
assertThat(getManagedEntities(session)).size().isEqualTo
;
assertThat(neymar.getId()).isNotNull();
int count = queryCount(«select count(*) from Football_Player where name=’Neymar'»);
assertThat(count).isEqualTo(0);
transaction.commit();
count = queryCount(«select count(*) from Football_Player where name=’Neymar'»);
assertThat(count).isEqualTo
;
Как только мы выполняемSession.save(entity), объекту присваивается значение идентичности, и он становится управляемымSession. Однако он может быть еще недоступен в базе данных, поскольку операция INSERT может быть отложена до конца единицы работы.
Список состояний
А теперь начинается самое интересное. Мы будем изучать состояния Entity-объектов. За все нужно платить, и за использование Hibernate тоже. Не думаешь же ты, что изучение HQL – это и есть такая плата? Нет, жизнь устроена немного сложнее.
Если у тебя есть какой-то Entity-объект, который ты можешь сохранять в базу с помощью Hibernate, то с точки зрения Hibernate у этого объекта может быть четыре состояния:
А чтобы тебя заинтересовать, добавлю к этой лекции вот такую картинку:

Заключение
Концепцияpersistence context является центральной для понимания жизненного цикла сущностей Hibernate. Мы прояснили жизненный цикл, изучив примеры кода, демонстрирующие каждый статус.
Как обычно, код, использованный в этой статье, находится вover on GitHub.





