Видове JPA заявки

1. Общ преглед

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

2. Настройка

Първо, нека дефинираме класа UserEntity, който ще използваме за всички примери в тази статия:

@Table(name = "users") @Entity public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

Има три основни типа JPA заявки:

  • Заявка , написана в синтаксис на Java Persistence Query Language (JPQL)
  • NativeQuery , написана в обикновен синтаксис на SQL
  • Criteria API Query , изградена програмно чрез различни методи

Нека ги изследваме.

3. Запитване

А за заявки е близка по синтаксис на SQL, и това е обикновено се използва за извършване на CRUD операции:

public UserEntity getUserByIdWithPlainQuery(Long id) { Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id"); jpqlQuery.setParameter("id", id); return (UserEntity) jpqlQuery.getSingleResult(); }

Тази заявка извлича съответстващия запис от потребителската таблица и също го свързва с обекта UserEntity .

Има два допълнителни подтипа заявка :

  • TypedQuery
  • NamedQuery

Нека ги видим в действие.

3.1. TypedQuery

Трябва да обърнем внимание на изявлението за връщане в предишния ни пример. JPA не може да изчисли какъв ще бъде типът на резултата от заявката и в резултат на това трябва да хвърлим.

Но JPA предоставя специален подтип Query, известен като TypedQuery. Това винаги е за предпочитане, ако предварително знаем типа на резултата от нашата заявка . Освен това прави нашия код много по-надежден и по-лесен за тестване.

Нека видим алтернатива на TypedQuery в сравнение с нашия първи пример:

public UserEntity getUserByIdWithTypedQuery(Long id) { TypedQuery typedQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class); typedQuery.setParameter("id", id); return typedQuery.getSingleResult(); }

По този начин получаваме по-силно въвеждане на текст безплатно, като избягваме възможните изключения за кастинг по пътя.

3.2. NamedQuery

Въпреки че можем динамично да дефинираме заявка за конкретни методи, те в крайна сметка могат да прераснат в трудна за поддържане кодова база. Ами ако можем да поддържаме общи заявки за използване на едно централизирано, лесно за четене място?

JPA също ни покри с това с друг подтип Query, известен като NamedQuery.

Ние дефинираме NamedQuery за самия клас Entity , предоставяйки централизиран, бърз и лесен начин за четене и намиране на свързани с Entity заявки.

Всички NamedQueries трябва да имат уникално име.

Нека да видим как можем да добавим NamedQuery към нашия клас UserEntity :

@Table(name = "users") @Entity @NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId") public class UserEntity { @Id private Long id; private String name; //Standard constructor, getters and setters. }

В @NamedQuery анотацията трябва да бъдат групирани в една @NamedQueries анотация, ако ние използваме Java, преди версия 8. От Java 8 напред, ние можем просто се повтаря @NamedQuery анотация на нашия Entity клас.

Използването на NamedQuery е много просто:

public UserEntity getUserByIdWithNamedQuery(Long id) { Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId"); namedQuery.setParameter("userId", id); return (UserEntity) namedQuery.getSingleResult(); }

4. NativeQuery

А NativeQuery е просто SQL заявка. Те ни позволяват да разгърнем пълната мощ на нашата база данни, тъй като можем да използваме патентовани функции, които не са налични в синтаксиса, ограничен от JPQL.

Това си струва. Ние губим преносимост на базата данни на нашето приложение с NativeQuery, защото нашият доставчик на JPA вече не може да абстрахира конкретни подробности от внедряването на базата данни или от доставчика.

Нека да видим как да използваме NativeQuery, който дава същите резултати като нашите предишни примери:

public UserEntity getUserByIdWithNativeQuery(Long id) { Query nativeQuery = getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class); nativeQuery.setParameter("userId", id); return (UserEntity) nativeQuery.getSingleResult(); }

Винаги трябва да обмисляме дали NativeQuery е единствената опция. През повечето време добрата JPQL заявка може да отговори на нашите нужди и най-важното е да поддържа ниво на абстракция от действителното внедряване на база данни.

Използването на NativeQuery не означава непременно да се заключим към един конкретен доставчик на база данни. В крайна сметка, ако нашите заявки не използват собствени SQL команди и използват само стандартен SQL синтаксис, смяната на доставчици не би трябвало да е проблем.

5. Заявка за API на критерии

Критериите за API заявки са програмно изградени, безопасни за типа заявки - донякъде подобни на JPQL заявки в синтаксис:

public UserEntity getUserByIdWithCriteriaQuery(Long id) { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class); Root userRoot = criteriaQuery.from(UserEntity.class); UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot) .where(criteriaBuilder.equal(userRoot.get("id"), id))) .getSingleResult(); return queryResult; }

Може да е обезсърчително да се използват заявки за API на критерии от първа ръка, но те могат да бъдат чудесен избор, когато трябва да добавим динамични елементи на заявка или когато са свързани с JPA Metamodel .

6. Заключение

В тази кратка статия научихме какво представляват JPA заявките, заедно с тяхното използване.

JPA заявките са чудесен начин да абстрахирате нашата бизнес логика от слоя ни за достъп до данни, тъй като можем да разчитаме на синтаксиса JPQL и да оставим избрания от нас доставчик на JPA да се справи с превода на заявките .

Целият код, представен в тази статия, е достъпен в GitHub.