Давайте начнем с простых вещей с создания сущности, точнее, с сохранения transient объекта в базе данных, т.е. перевода его в
состояние persistent . Сохраняют сущность
в базе данных методом .save(),
особенность этого метода в том, что он сразу возвращает первичный ключ
сущности и при этом генерирует sql команду insert, если его первичным
ключом является поле для которого
используется метод генерации “identity”
, а не “sequence”.
Используется в рамках одной транзакции. Смотрим
листинг:
session.getTransaction().begin();
Person person = new Person();
…
Long
id = (Long) session.save(person);
…
session.getTransaction().begin();
Так же есть метод .persist() который, как и
метод .save() переводит объект из
состояния transient в
состояние persistent. В
противоположность методу .save(), .persist() не пытается сразу же вернуть нам первичный ключ сущности, его применяют, если
операции у нас продолжительны по времени, вызов sql команды
insert может быть отложен на момент комита транзакции .commit() или вызова метода .flush(). Используется обычно
для длительных по времени и сложных последовательностей операций вне рамках
транзакций. Смотрим листинг:
session = sessionFactory.openSession();
session.getTransaction().begin();
Person person = new Person();
…
session.getTransaction().commit();
…
session.persist(person);
//вызов вне рамках транзакции!
…
session.getTransaction().begin();
session.flush();
session.close();
Если некоторые поля сущности заполняются или
проверяются различными триггерами базы данных, то следует пользоваться вот
такой связкой сохранения:
session.save(person);
session.flush();
session.refresh(person);
где метод
.flush() сначала скидывает все изменения в базу данных, а метод .refresh() обновляет
данные после выполнения логики триггеров. И так, если у нас объект
сущности связан с сессией, то он
находится в состоянии persistent,
как мы только выходим за рамки сессии, сущность переходит в состояние detached. В этом состоянии объект сущности может
быть изменен, например такой метод
используется во всех web приложениях. Для того что бы
изменения сделанные вне сессии/транзакции применились для detached объекта, нужно обратно перевести его в состояние persistent, это делается
методом .update(). Смотрим листинг:
Long id =
(Long) session.save(person);
…
session.getTransaction().commit();
session.close();
…
person.setFirstName("Oleg");
…
session =
sessionFactory.openSession();
session.getTransaction().begin();
session.update(person);
…
session.getTransaction().commit();
session.close();
Но в этом примере для
метода .update() есть свой подводный камень, допустим, что у нас в сессии есть объект с
первичным ключом сущности, который уже
связан с сессией и такой же ключ имеет наш detached
объект. Т. е. если мы попытаемся выполнить по нему метод
.update(), то мы получим исключительную ситуацию org.hibernate.NonUniqueObjectException и так сгенерируем все это, добавим строчку кода Person person2 =
(Person)session.get(Person.class,id); перед session.update(person). Смотрим листинг:
Long id = (Long) session.save(person);
…
session.getTransaction().commit();
session.close();
…
person.setFirstName("Oleg");
…
session =
sessionFactory.openSession();
session.getTransaction().begin();
Person person2 =
(Person)session.get(Person.class,id);
session.update(person); //
получим ошибку
org.hibernate.NonUniqueObjectException
…
session.getTransaction().commit();
session.close();
Что бы избежать исключительной
ситуации мы должны применить .merge(), эта команда подобна команде saveOrUpdateCopy() в Hibernate 2. Она
возвращает нам ссылку на копию новой
сущности, при этом берется persistent объект с таким
же ключом как у detached объекта, все изменения перезаписываются с detached
объекта поверх persistent объекта. После
этого мы имеем два объекта, detached
объект и копию ссылки на persistent объект с
копированными значениями полей detached сущности. Далее с копией мы работаем как с persistent объектом и все изменения, которые мы хотим
сохранить в базе данных, мы применяем к этой копии, т. е. метод .merge()
не переводит сущность из detached состояния в состояние persistent как метод .update(). Рассмотрим все на примере, смотрим на листинг:
Person person = new Person();
person.setFirstName("Vitaly");
person.setSecondName("Lopanov");
Long id = (Long)
session.save(person);
session.getTransaction().commit();
session.close();
person.setFirstName("Oleg");
session =
sessionFactory.openSession();
session.getTransaction().begin();
Person person2 =
(Person)session.get(Person.class,id);
System.out.printf("Person
select person2: %s\n", person2);
Person person3 =
(Person)session.merge(person);
person.setFirstName("Vika");\\ эти
изменения ни когда не попадут в базу данных
\\
дальше нужно работать с копией person3 как с persistent объектом.
System.out.printf("Person
select person2: %s\n", person2);
if (person != person3)
{System.out.format("ссылка на новый
instance\n");}
session.flush();
person =
(Person)session.get(Person.class,id);
System.out.printf("Person
select: %s\n", person);
\\ Вывод:
Person select: Person{id=1, firstName='Oleg', secondName='Lopanov'}
Есть еще один
интересный метод .saveOrUpdate() который
вобрал в себя поведение двух методов .save() и .update(). Если нет объекта,
то метод .saveOrUpdate() ведет
себя как .save() и создает persistent объект в
сессии, иначе он ведет себя как метод .update() обновляет объект. Хотелось бы
сказать по поводу применения методов .save() , .update(),
.saveOrUpdate(), если ваша
сущность находиться в состоянии persistent, то не
нужно писать лишнии команды и повторно переводить сущность в состояние persistent, это типично
для новичков. Смотрим листинг:
session = sessionFactory.openSession();
session.getTransaction().begin();
Person person = (Person)session.get(Person.class,id); /* метод
.get()возвращает сущность
person которая находится
в состоянии persistent и все изменения
которые мы предпримем с сущностью, автоматом
перепишутся в Базу Данных после выполнения методов .flush() или .commit() */
person.setFirstName("Vitaly");
session.saveOrUpdate(person); /* лишний вызов
метода .saveOrUpdate() типично для новичков */
session.flush();
Для удаления сущности
нужно выполнить метод сессии .delete(),
сущность будет переведена в состояние removed, а после
выполнения методов .flush() или .commit() будет удалена и
из таблицы базы данных. Нужно учитывать
одну особенность, если у сущности есть “дети” они могут остаться без “родителей”, т.е.
сначала нужно удалить зависимые объекты
от этой сущности, потом и саму сущность. Смотрим листинг:
session = sessionFactory.openSession();
session.getTransaction().begin();
Person person =
(Person)session.get(Person.class,id);
session.delete(person);
session.flush();
Прочитать сущность
можно несколькими способами, методы .get() и .load() возвращают нам сущности по заранее известному
нам ключу, в чем отличие этих методов я писал выше, не будем заострять на них
внимание и повторятся. Для чтения множества “массива” сущностей можно прибегнуть к двум методам, первый это вернуть
сразу все записи методом .list(), смотрим листинг:
List<Person> persons =
session.createCriteria(Person.class).list();
for (Person p: persons ) {
System.out.printf("%s\n",
p);
}
Второй способ это работать с итератором (Iterator), его нужно и можно использовать для повышения
производительности запроса данных, если
запрос находиться в кэше второго уровня и выборка данных идет из кэша. Если нет
данных в кэше, то запрос с итератором будет работать дольше, чем запрос
методом .list(). Смотрим листинг:
Iterator<Person> iterator
= session.createQuery("from Person").iterate();
while (iterator.hasNext()) {
Person p = iterator.next();
System.out.printf("%s\n", p);
}
Постраничная выборка или pagination, мы можем ограничить результаты выборки и обрабатывать
всё, малыми порциями в этом нам помогут две команды .setMaxResults(),
количество сущностей, сколько вернуть в запросе и начиная с какой сущности .setFirstResult().
Постраничная выборка реализуется обычно внутреннем механизмом базы данных. Например,
вывести 5 сущностей, пропустив десять первых сущностей в выборке, смотрим на
листинг:
persons =
session.createCriteria(Person.class).setMaxResults(5).setFirstResult(10).list();
for (Person p: persons ) {
System.out.printf("%s\n", p);
}
Комментариев нет:
Отправить комментарий