Upotreba parametara upita JPA

1. Uvod

Izgradnja upita pomoću JPA nije teška; međutim, ponekad zaboravimo na jednostavne stvari koje čine veliku razliku.

Jedna od tih stvari su parametri upita JPA i o tome ćemo razgovarati.

2. Što su parametri upita?

Počnimo s objašnjenjem što su parametri upita.

Parametri upita način su za izgradnju i izvršavanje parametriziranih upita. Dakle, umjesto:

ODABERITE * OD zaposlenika e WHERE e.emp_number = '123';

Napravili bismo:

ODABERITE * OD zaposlenika e GDJE e.emp_number =?;

Korištenjem izraza pripremljenog za JDBC, moramo postaviti parametar prije izvođenja upita:

pStatement.setString (1, 123);

3. Zašto bismo trebali koristiti parametre upita?

Umjesto da koristimo parametre upita, mogli bismo odabrati literale, to ipak nije preporučeni način, kao što ćemo sada vidjeti.

Prepišimo prethodni upit da privučemo zaposlenike em_broj koristeći JPA API, ali umjesto da koristimo parametar, koristit ćemo literal kako bismo mogli jasno ilustrirati situaciju:

Niz empNumber = "A123"; TypedQuery query = em.createQuery ("SELECT e FROM Employee e WHERE e.empNumber = '" + empNumber + "'", Employee.class); Zaposlenik zaposlenik = query.getSingleResult ();

Ovaj pristup ima nekoliko nedostataka:

  • Parametri za ugradnju uvode sigurnosni rizik koji nas čini ranjivima na JPQL napade injekcije. Umjesto očekivane vrijednosti, napadač može ubaciti bilo koji neočekivani i moguće opasni JPQL izraz
  • Ovisno o provedbi JPA koju koristimo i heuristici naše aplikacije, predmemorija upita može se iscrpiti. Novi upit može se graditi, kompajlirati i predmemorirati svaki put kada ga koristimo sa svakom novom vrijednošću / parametrom. To u najmanju ruku neće biti učinkovito, a može dovesti i do neočekivanog OutOfMemoryError

4. Parametri upita JPA

Slično JDBC pripremljenim parametrima izraza, JPA specificira dva različita načina za pisanje parametriziranih upita pomoću:

  • Pozicijski parametri
  • Imenovani parametri

Možemo koristiti pozicijske ili imenovane parametre, ali ih ne smijemo miješati unutar istog upita.

4.1. Pozicijski parametri

Korištenje pozicijskih parametara jedan je od načina da se izbjegnu prethodno navedeni problemi.

Pogledajmo kako bismo napisali takav upit uz pomoć pozicijskih parametara:

TypedQuery query = em.createQuery ("SELECT e FROM Employee e WHERE e.empNumber =? 1", Employee.class); Niz empNumber = "A123"; Zaposlenik zaposlenik = query.setParameter (1, empNumber) .getSingleResult ();

Kao što smo vidjeli u prethodnom primjeru, te parametre prijavljujemo u upitu upisujući upitnik iza kojeg slijedi pozitivni cijeli broj. Počet ćemo s 1 i krenite naprijed, povećavajući ga svaki put za jedan.

Isti parametar možemo koristiti više puta u okviru istog upita što čini te parametre sličnijima imenovanih parametara.

Numeriranje parametara vrlo je korisna značajka jer poboljšava upotrebljivost, čitljivost i održavanje.

Vrijedno je to spomenuti pozicijsko vezanje parametara podržavaju i nativni SQL upiti.

4.2. Pozicijski parametri vrednovani zbirkom

Kao što je prethodno rečeno, možemo koristiti i parametre vrijedne kolekcije:

TypedQuery query = entityManager.createQuery ("SELECT e FROM Employee e WHERE e.empNumber IN (? 1)", Employee.class); Popis empNumbers = Arrays.asList ("A123", "A124"); Popis zaposlenika = query.setParameter (1, empNumbers) .getResultList ();

4.3. Imenovani parametri

Imenovani parametri prilično su slični pozicijskim parametrima; međutim, njihovom uporabom parametre činimo eksplicitnijima i upit postaje čitljiviji:

TypedQuery query = em.createQuery ("SELECT e FROM Employee e WHERE e.empNumber =: number", Employee.class); Niz empNumber = "A123"; Zaposlenik zaposlenik = query.setParameter ("broj", empNumber) .getSingleResult ();

Prethodni uzorak upita jednak je prvom, ali mi smo ga koristili :broj, imenovani parametar, umjesto ?1.

Možemo vidjeti da smo parametar deklarirali dvotočkom, a slijedi ga identifikator niza (JPQL identifikator) koji je rezervirano mjesto za stvarnu vrijednost koja će biti postavljena za vrijeme izvođenja. Prije izvođenja upita, parametar ili parametri moraju se postaviti izdavanjem setParameter metoda.

Jedna zanimljiva stvar koju treba primijetiti je ta the TypedQuery podržava ulančavanje metoda što postaje vrlo korisno kada se mora postaviti više parametara.

Idemo naprijed i stvorimo varijaciju prethodnog upita pomoću dva imenovana parametra da ilustriramo ulančavanje metoda:

TypedQuery query = em.createQuery ("SELECT e FROM Employee e WHERE e.name =: name AND e.age =: empAge", Employee.class); String empName = "John Doe"; int empAge = 55; Popis zaposlenika = upit .setParameter ("ime", empName) .setParameter ("empAge", empAge) .getResultList ();

Ovdje dolazimo do svih zaposlenika s navedenim imenom i dobi. Kao što jasno vidimo i može se očekivati, možemo graditi upite pomoću više parametara i onoliko pojavljivanja koliko je potrebno.

Ako iz nekog razloga trebamo koristiti isti parametar više puta u okviru istog upita, samo ga moramo postaviti jednom izdavanjem "setParameter”Metoda. Tijekom izvođenja, navedene vrijednosti zamijenit će svaku pojavu parametra.

Na kraju, vrijedi to spomenuti specifikacija Java Persistence API ne zahtijeva da imenovani parametri budu podržani od strane izvornih upita. Čak i kad ga neke implementacije poput Hibernate podržavaju, moramo uzeti u obzir da ako ga koristimo, upit neće biti toliko prenosiv.

4.4. Imenovani parametri vrednovani zbirkom

Da bismo bili jasniji, demonstrirajmo i kako ovo funkcionira s parametrima vrijednim zbirke:

TypedQuery query = entityManager.createQuery ("SELECT e FROM Employee e WHERE e.empNumber IN (: numbers)", Employee.class); Popis empNumbers = Arrays.asList ("A123", "A124"); Popis zaposlenika = query.setParameter ("brojevi", empNumbers) .getResultList ();

Kao što vidimo, djeluje na sličan način kao i pozicijski parametri.

5. Parametri upita kriterija

JPA upit može se stvoriti korištenjem API-ja JPA kriterija, što službena dokumentacija Hibernate-a objašnjava vrlo detaljno.

U ovoj vrsti upita parametre predstavljamo pomoću objekata umjesto imena ili indeksa.

Izgradimo opet isti upit, ali ovaj put pomoću API-ja kriterija kako bismo pokazali kako se rukuje parametrima upita kada se radi KriterijiPitanje:

CriteriaBuilder cb = em.getCriteriaBuilder (); CriteriaQuery cQuery = cb.createQuery (Employee.class); Korijen c = cQuery.from (Employee.class); ParameterExpression paramEmpNumber = cb.parameter (String.class); cQuery.select (c) .where (cb.equal (c.get (Employee_.empNumber), paramEmpNumber)); Upit TypedQuery = em.createQuery (cQuery); Niz empNumber = "A123"; query.setParameter (paramEmpNumber, empNumber); Zaposlenik zaposlenik = query.getResultList ();

Za ovu vrstu upita, mehanika parametra je malo drugačija jer koristimo objekt parametra, ali u osnovi nema razlike.

U prethodnom primjeru možemo vidjeti upotrebu Zaposlenik_ razred. Ovu smo klasu generirali pomoću hibernate generatora metamodela. Te su komponente dio statičkog JPA metamodela, koji omogućuje izradu upita s kriterijima na strogo otkucan način.

6. Zaključak

U ovom smo se članku usredotočili na mehaniku izrade upita pomoću parametara upita JPA ili ulaznih parametara.

Saznali smo da imamo dvije vrste parametara upita, pozicijski i imenovani. Na nama je koji će najbolje odgovarati našim ciljevima.

Također je vrijedno napomenuti da svi parametri upita moraju biti jednoznačni, osim za u izrazi. Za u izraze, možemo koristiti ulazne parametre vrijedne kolekcije, poput nizova ili Popiss kao što je prikazano u prethodnim primjerima.

Izvorni kod ovog vodiča, kao i obično, dostupan je na GitHubu.


$config[zx-auto] not found$config[zx-overlay] not found