JPA-forespørgselsparametre

1. Introduktion

Opbygning af forespørgsler ved hjælp af JPA er ikke svært; dog glemmer vi nogle gange enkle ting, der gør en enorm forskel.

En af disse ting er JPA-forespørgselsparametre, og det er det, vi skal tale om.

2. Hvad er forespørgselsparametre?

Lad os starte med at forklare, hvad forespørgselsparametre er.

Forespørgselsparametre er en måde at opbygge og udføre parametriserede forespørgsler på. Så i stedet for:

VÆLG * FRA medarbejdere e WHERE e.emp_number = '123';

Vi ville gøre:

VÆLG * FRA medarbejdere e HVOR e.emp_nummer =?;

Ved at bruge en JDBC-forberedt erklæring skal vi indstille parameteren, før forespørgslen udføres:

pStatement.setString (1, 123);

3. Hvorfor skal vi bruge forespørgselsparametre?

I stedet for at bruge forespørgselsparametre kunne vi have valgt at bruge bogstaver, men det er ikke den anbefalede måde at gøre det på, som vi ser nu.

Lad os omskrive den forrige forespørgsel for at få medarbejdere med emp_nummer ved hjælp af JPA API, men i stedet for at bruge en parameter bruger vi en bogstavelig, så vi tydeligt kan illustrere situationen:

Streng empNumber = "A123"; TypedQuery forespørgsel = em.createQuery ("VÆLG e FRA medarbejder e HVOR e.empNumber = '" + empNumber + "'", Medarbejder.klasse); Medarbejdermedarbejder = forespørgsel.getSingleResult ();

Denne tilgang har nogle ulemper:

  • Integreringsparametre indfører en sikkerhedsrisiko, der gør os sårbare over for JPQL-injektionsangreb. I stedet for den forventede værdi kan en angriber injicere ethvert uventet og muligvis farligt JPQL-udtryk
  • Afhængigt af den JPA-implementering, vi bruger, og heuristikken i vores applikation, kan forespørgselens cache muligvis blive opbrugt. En ny forespørgsel kan blive bygget, kompileret og cachelagret hver gang vi bruger den med hver nye værdi / parameter. I det mindste er det ikke effektivt, og det kan også føre til en uventet OutOfMemoryError

4. JPA-forespørgselsparametre

Svarende til JDBC-forberedte sætningsparametre specificerer JPA to forskellige måder at skrive parametriserede forespørgsler ved hjælp af:

  • Positionsparametre
  • Navngivne parametre

Vi kan bruge enten positionelle eller navngivne parametre, men vi må ikke blande dem inden for samme forespørgsel.

4.1. Positionsparametre

Brug af positionsparametre er en måde at undgå de ovennævnte problemer opført tidligere.

Lad os se, hvordan vi ville skrive en sådan forespørgsel ved hjælp af positionsparametre:

TypedQuery-forespørgsel = em.createQuery ("VÆLG e FRA medarbejder e HVOR e.empNumber =? 1", Medarbejder.klasse); Streng empNumber = "A123"; Medarbejdermedarbejder = forespørgsel.setParameter (1, empNumber) .getSingleResult ();

Som vi har set i det foregående eksempel, vi erklærer disse parametre i forespørgslen ved at skrive et spørgsmålstegn efterfulgt af et positivt heltal. Vi starter med 1 og bevæg dig fremad, stig den med hver gang.

Vi bruger muligvis den samme parameter mere end én gang inden for samme forespørgsel, hvilket gør disse parametre mere ens med de navngivne parametre.

Parameternummerering er en meget nyttig funktion, da den forbedrer brugervenlighed, læsbarhed og vedligeholdelse.

Det er værd at nævne det positionel parameterbinding understøttes også af native SQL-forespørgsler.

4.2. Samlingsværdipositionsparametre

Som tidligere nævnt kan vi også bruge indsamlingsværdiparametre:

TypedQuery-forespørgsel = entityManager.createQuery ("SELECT e FROM Employee e WHERE e.empNumber IN (? 1)", Employee.class); Liste empNumbers = Arrays.asList ("A123", "A124"); Liste medarbejdere = query.setParameter (1, empNumbers) .getResultList ();

4.3. Navngivne parametre

Navngivne parametre svarer meget til positionsparametre; dog ved at bruge dem gør vi parametrene mere eksplicitte, og forespørgslen bliver mere læsbar:

TypedQuery-forespørgsel = em.createQuery ("VÆLG e FRA medarbejder e HVOR e.empNumber =: antal", Medarbejder.klasse); Streng empNumber = "A123"; Medarbejdermedarbejder = query.setParameter ("nummer", empNumber) .getSingleResult ();

Den forrige prøveforespørgsel er den samme som den første, men vi har brugt :nummer, en navngivet parameter i stedet for ?1.

Vi kan se, at vi erklærede parameteren med et kolon efterfulgt af en streng-id (JPQL-identifikator), som er en pladsholder for den aktuelle værdi, der indstilles ved kørsel. Før forespørgslen udføres, skal parameteren eller parametrene indstilles ved at udstede sæt Parameter metode.

En interessant ting at bemærke er, at det TypedQuery understøtter metoden kæde hvilket bliver meget nyttigt, når der skal indstilles flere parametre.

Lad os gå videre og oprette en variation af den forrige forespørgsel ved hjælp af to navngivne parametre for at illustrere metoden sammenkædning:

TypedQuery-forespørgsel = em.createQuery ("VÆLG e FRA medarbejder e HVOR e.name =: navn OG e.age =: empAge", Medarbejder.klasse); String empName = "John Doe"; int empAge = 55; Liste medarbejdere = forespørgsel .setParameter ("navn", empName) .setParameter ("empAge", empAge) .getResultList ();

Her henter vi alle medarbejdere med det angivne navn og alder. Som vi tydeligt ser, og man kan forvente, kan vi oprette forespørgsler med flere parametre og så mange forekomster af dem som krævet.

Hvis vi af en eller anden grund har brug for at bruge den samme parameter mange gange inden for den samme forespørgsel, er vi bare nødt til at indstille den en gang ved at udstede "sæt Parameter”Metode. Ved kørsel erstatter de angivne værdier hver forekomst af parameteren.

Endelig er det værd at nævne det Java Persistence API-specifikationen kræver ikke, at navngivne parametre understøttes af indfødte forespørgsler. Selv når nogle implementeringer som Hibernate understøtter det, skal vi tage højde for, at hvis vi bruger det, vil forespørgslen ikke være så bærbar.

4.4. Samlingsværdige navngivne parametre

Af klarhedshensyn skal vi også demonstrere, hvordan dette fungerer med samlingsværdiparametre:

TypedQuery-forespørgsel = entityManager.createQuery ("VÆLG e FRA medarbejder e HVOR e.empNumber IN (: tal)", Medarbejder.klasse); Liste empNumbers = Arrays.asList ("A123", "A124"); Liste medarbejdere = query.setParameter ("numbers", empNumbers) .getResultList ();

Som vi kan se, fungerer det på samme måde som positionsparametre.

5. Kriterier forespørgselsparametre

En JPA-forespørgsel kan bygges ved hjælp af JPA Criteria API, som Hibernates officielle dokumentation forklarer i detaljer.

I denne type forespørgsel repræsenterer vi parametre ved hjælp af objekter i stedet for navne eller indekser.

Lad os bygge den samme forespørgsel igen, men denne gang ved hjælp af Criteria API til at demonstrere, hvordan man håndterer forespørgselsparametre, når man beskæftiger sig med Kriteriespørgsmål:

CriteriaBuilder cb = em.getCriteriaBuilder (); CriteriaQuery cQuery = cb.createQuery (Medarbejder.klasse); Root c = cQuery.from (Medarbejder.klasse); ParameterExpression paramEmpNumber = cb.parameter (String.class); cQuery.select (c) .where (cb.equal (c.get (Employee_.empNumber), paramEmpNumber)); TypedQuery-forespørgsel = em.createQuery (cQuery); Streng empNumber = "A123"; query.setParameter (paramEmpNumber, empNumber); Medarbejdermedarbejder = query.getResultList ();

For denne type forespørgsel er parameterens mekanik lidt anderledes, da vi bruger et parameterobjekt, men i det væsentlige er der ingen forskel.

I det foregående eksempel kan vi se brugen af Medarbejder_ klasse. Vi genererede denne klasse med Hibernate metamodel-generatoren. Disse komponenter er en del af den statiske JPA-metamodel, som gør det muligt at oprette kriterieforespørgsler på en stærkt skrevet måde.

6. Konklusion

I denne artikel har vi fokuseret på mekanikken i bygningsforespørgsler ved hjælp af JPA-forespørgselsparametre eller inputparametre.

Vi har lært, at vi har to typer forespørgselsparametre, positionelle og navngivne. Det er op til os, hvilken der bedst passer til vores mål.

Det er også værd at bemærke, at alle forespørgselsparametre skal være enkeltværdige bortset fra i udtryk. Til i udtryk, kan vi bruge indsamlingsværdiske inputparametre, såsom arrays eller Listes som vist i de foregående eksempler.

Kildekoden til denne vejledning er som sædvanlig tilgængelig på GitHub.


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