Статьи

Окончательный список запросов и советов JPA — часть 3

Прежде чем читать третью часть, вспомните первую и вторую часть серии

JPA: создание объекта из запроса

JPA позволяет нам создавать объекты внутри запроса, используя только те значения, которые нам нужны:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.model;
 
public class PersonDogAmountReport {
 private int dogAmount;
 private Person person;
 
 public PersonDogAmountReport(Person person, int dogAmount) {
  this.person = person;
  this.dogAmount = dogAmount;
 }
 
 public int getDogAmount() {
  return dogAmount;
 }
 
 public void setDogAmount(int dogAmount) {
  this.dogAmount = dogAmount;
 }
 
 public Person getPerson() {
  return person;
 }
 
 public void setPerson(Person person) {
  this.person = person;
 }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.main;
 
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.Query;
 
import com.model.PersonDogAmountReport;
 
public class Page13 {
 
 @SuppressWarnings('unchecked')
 public static void main(String[] args) {
  CodeGenerator.startConnection();
 
  CodeGenerator.generateData();
 
  EntityManager em = CodeGenerator.getEntityManager();
 
  Query query = em.createQuery('select new com.model.PersonDogAmountReport(p, size(p.dogs)) from Person p group by p.id');
 
  List<PersonDogAmountReport> persons = query.getResultList();
  for (PersonDogAmountReport personReport : persons) {
   System.out.println(personReport.getPerson().getName() + ' has: ' + personReport.getDogAmount() + ' dogs.');
  }
 
  CodeGenerator.closeConnection();
 }
}

Обратите внимание, что внутри нашего запроса мы создаем новый объект. Хорошей новостью является то, что вы можете создать любой объект, он не должен быть сущностью. Вам просто нужно передать полный путь к классу, и JPA будет обрабатывать создание новых классов.

Это очень полезная функция для использования с отчетами, в которых вам нужны специфические поля, но эти поля не существуют в объекте.

JPQL: массовое обновление и удаление

Иногда нам нужно выполнить операцию, чтобы обновить несколько строк в базе данных таблицы. Например, обновить всех лиц в возрасте старше 70 лет и определить, чем пожилые люди.

Вы можете запустить групповое обновление / удаление следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.main;
 
import javax.persistence.EntityManager;
import javax.persistence.Query;
 
import com.model.Person;
 
public class Page14 {
 
 public static void main(String[] args) {
  CodeGenerator.startConnection();
 
  CodeGenerator.generateData();
 
  EntityManager em = CodeGenerator.getEntityManager();
 
  em.clear();
  Query query = em.createQuery('update Person p set p.name = 'Fluffy, the destroyer of worlds!'');
  query.executeUpdate();
 
  query = em.createQuery('select p from Person p where p.id = 4');
 
  Person person = (Person) query.getSingleResult();
 
  System.out.println('My new name is: ' + person.getName());
 
  query = em.createQuery('delete from Person p where p.dogs is empty');
  query.executeUpdate();
 
  query = em.createQuery('select p from Person p');
 
  System.out.println('We had 6, but was found ' + query.getResultList().size() + ' persons in the database');
 
  CodeGenerator.closeConnection();
 }
}

Каскадная опция не будет срабатывать в этом сценарии; вы не сможете удалить объект и надеетесь, что JPA удалит каскадные объекты в отношении. Целостность данных базы данных принадлежит разработчику, когда мы говорим о массовых операциях. Если вы хотите удалить объект из базы данных и его взаимосвязей, вам необходимо обновить объект, установив для связи нулевое значение, перед выполнением удаления.

Мы можем определить этот вид операции как очень опасную операцию. Если мы прокомментируем строку 17 (« em.clear (); «), мы увидим, что имя человека остается неизменным после обновления.

« Проблема » заключается в том, что контекст постоянства сохраняет все данные в памяти « подключенными », но эти виды массовых операций не обновляют контекст постоянства. У нас будет операция в нашей базе данных, но она еще не нашла отражения в нашем контексте постоянства. Такая ситуация может вызвать проблемы с синхронизацией.

Представьте себе следующий сценарий:

  • Транзакция начата.
  • Персона А сохраняется в базе данных с помощью метода em.persist ().
  • Персона B имеет свое имя, обновленное до «Louanne» с помощью метода em.merge ().
  • Лицо А будет удалено массовым удалением.
  • Персона B имеет свое имя, обновленное до «Фернанда» массовым обновлением.
  • Транзакция заканчивается.

Что произойдет в этом сценарии? Персона A была удалена массовыми операциями, но контекст постоянства попытается сохранить его в базе данных. Персона B получила свое имя, обновленное до Фернанды, но Контекст Постоянства попытается обновить до Луаны.

Не существует поведения по умолчанию для такой ситуации, но есть решения, которые мы можем использовать, чтобы избежать этих проблем:

  • Начать новую транзакцию перед массовой операцией. Если новая транзакция началась только для массовой операции, то после ее завершения обновления / удаления будут выполняться в базе данных. У вас не будет менеджера сущностей, пытающегося использовать данные, которые еще не были записаны в базу данных.
  • Вызовите метод entityManager.clear () перед массовой операцией: если вы вызовете этот метод, вы заставите контекст постоянства освободить все кэшированные данные. После массовой операции, если вы используете метод find, контекст постоянства получит данные из базы данных, потому что вы очистили кэшированные данные перед массовой операцией.

Вызов метода clear () не является «серебряной пулей», если вы используете его слишком много раз, это может привести к проблемам с производительностью. Если в вашем постоянном контексте много кэшированных объектов, и вы вызываете метод clear (), ваш постоянный контекст должен будет выполнить много «поездок», чтобы снова получить необходимые данные. Контекст постоянства имеет прекрасный контроль над кэшем данных и должен им воспользоваться.

Массовые операции — это вариант, который поможет нам в нескольких ситуациях, но вы должны использовать его осторожно.

JPA: критерии

JPA — это хороший фреймворк для выполнения ваших запросов, но критерии — это не хороший способ выполнения запросов с JPA.

Критерии JPA слишком многословны, сложны, и для выполнения некоторых базовых запросов требуется слишком много кода. К сожалению, это не так просто, как Критерии гибернации.

Код ниже покажет простой код Критерии, но мы не увидим больше этой темы. Я уже прочитал 3 книги об EJB / JPA, и ни одна книга не говорила об этом.

Код ниже имеет код критерия:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.main;
 
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaQuery;
 
import com.model.Person;
 
public class Page15 {
 
 @SuppressWarnings({ 'unchecked', 'rawtypes' })
 public static void main(String[] args) {
  CodeGenerator.startConnection();
 
  CodeGenerator.generateData();
 
  EntityManager em = CodeGenerator.getEntityManager();
 
  CriteriaQuery criteriaQuery = em.getCriteriaBuilder().createQuery();
  criteriaQuery.select(criteriaQuery.from(Person.class));
 
  List<Person> result = em.createQuery(criteriaQuery).getResultList();
 
  System.out.println('Found ' + result.size() + ' persons.');
 
  CodeGenerator.closeConnection();
 }
}

Мне жаль говорить, что я думаю о Criteria, как это здесь, но на данный момент я не вижу простоты использования Criteria в вашем коде, кроме как для A ListALL.

Код выше кода легко применяется к универсальному DAO, было бы проще перечислить все объекты по нему.

Следующая ссылка показывает общий DAO в приложении: полное WebApplication JSF EJB JPA JAAS .

Конец!

Я надеюсь, что этот пост может помочь вам.

Нажмите здесь, чтобы скачать исходный код.

Вам не нужно будет редактировать какую-либо конфигурацию для запуска кода этого поста, просто импортируйте его в Eclipse.

Если у вас есть какие-либо сомнения / комментарии, просто оставьте сообщение ниже.

До скорой встречи.

Полезные ссылки:

  • http://www.mkyong.com/hibernate/how-to-display-hibernate-sql-parameter-values-log4j/
  • http://stackoverflow.com/questions/1659030/how-to-get-the-database-time-with-jpql
  • Pro EJB 3: API персистентности Java, Майк Кит, Меррик Шинкариол
  • Enterprise JavaBeans 3.0 — Ричард Монсон-Хейфель, Билл Берк

Ссылка: JPA Запросы и советы от нашего партнера JCG Хеберта Коэльо в блоге uaiHebert .