JPA Query Parameters Usage

1. Introduksjon

Å bygge spørsmål ved hjelp av JPA er ikke vanskelig; imidlertid glemmer vi noen ganger enkle ting som gjør en enorm forskjell.

En av disse tingene er JPA-spørringsparametere, og dette er hva vi skal snakke om.

2. Hva er spørringsparametere?

La oss starte med å forklare hva parametrene er.

Spørsmålsparametere er en måte å bygge og utføre parametrerte spørsmål på. Så i stedet for:

VELG * FRA ansatte e WHERE e.emp_number = '123';

Vi ville gjort:

VELG * FRA ansatte e HVOR e.emp_nummer =?;

Ved å bruke en JDBC utarbeidet uttalelse, må vi sette parameteren før du utfører spørringen:

pStatement.setString (1, 123);

3. Hvorfor skal vi bruke søkeparametere?

I stedet for å bruke spørringsparametere kunne vi ha valgt å bruke bokstaver, men det er ikke den anbefalte måten å gjøre det på, som vi ser nå.

La oss omskrive forrige spørring for å få ansatte etter emp_number ved hjelp av JPA API, men i stedet for å bruke en parameter, bruker vi bokstavelig, slik at vi tydelig kan illustrere situasjonen:

Streng empNumber = "A123"; TypedQuery query = em.createQuery ("SELECT e FROM Employee e WHERE e.empNumber = '" + empNumber + "'", Employee.class); Ansatt ansatt = query.getSingleResult ();

Denne tilnærmingen har noen ulemper:

  • Innbyggingsparametere innfører en sikkerhetsrisiko som gjør oss sårbare for JPQL-injeksjonsangrep. I stedet for den forventede verdien kan en angriper injisere ethvert uventet og muligens farlig JPQL-uttrykk
  • Avhengig av JPA-implementeringen vi bruker og heuristikken til applikasjonen vår, kan spørringsbufferen bli oppbrukt. Et nytt spørsmål kan bygges, kompileres og hurtigbufres hver gang vi bruker det med hver nye verdi / parameter. I det minste vil det ikke være effektivt, og det kan også føre til en uventet OutOfMemoryError

4. JPA-spørringsparametere

I likhet med JDBC utarbeidede utsagnsparametere spesifiserer JPA to forskjellige måter å skrive parametrerte spørsmål ved å bruke:

  • Posisjonsparametere
  • Navngitte parametere

Vi kan bruke enten posisjonsparametere eller navngitte parametere, men vi må ikke blande dem i samme spørring.

4.1. Posisjonsparametere

Å bruke posisjonsparametere er en måte å unngå de nevnte problemene som er oppført tidligere.

La oss se hvordan vi vil skrive et slikt spørsmål ved hjelp av posisjonsparametere:

TypedQuery query = em.createQuery ("VELG e FRA ansatt e WHERE e.empNumber =? 1", Employee.class); Streng empNumber = "A123"; Ansatt ansatt = query.setParameter (1, empNumber) .getSingleResult ();

Som vi har sett i forrige eksempel, vi erklærer disse parametrene i spørringen ved å skrive et spørsmålstegn etterfulgt av et positivt heltall. Vi begynner med 1 og gå fremover, øk den hver gang.

Vi kan bruke den samme parameteren mer enn én gang i samme spørring, noe som gjør disse parameterne mer lik navngitte parametere.

Parameternummerering er en veldig nyttig funksjon siden den forbedrer brukervennlighet, lesbarhet og vedlikehold.

Det er verdt å nevne det posisjonsparameterbinding støttes også av innfødte SQL-spørsmål.

4.2. Samlingsverdige posisjonsparametere

Som tidligere nevnt kan vi også bruke parametere som samler inn:

TypedQuery spørring = entityManager.createQuery ("VELG e FRA medarbeider e WHERE e.empNumber IN (? 1)", Employee.class); Liste empNumbers = Arrays.asList ("A123", "A124"); Liste ansatte = query.setParameter (1, empNumbers) .getResultList ();

4.3. Navngitte parametere

Navngitte parametere er ganske like posisjonsparametere; ved å bruke dem, gjør vi imidlertid parameterne mer eksplisitte, og spørringen blir mer lesbar:

TypedQuery query = em.createQuery ("VELG e FRA ansatt e WHERE e.empNumber =: nummer", Employee.class); Streng empNumber = "A123"; Ansatt ansatt = query.setParameter ("nummer", empNumber) .getSingleResult ();

Den forrige eksempelspørringen er den samme som den første, men vi har brukt :Nummer, en navngitt parameter, i stedet for ?1.

Vi kan se at vi erklærte parameteren med et kolon etterfulgt av en strengidentifikator (JPQL-identifikator) som er en plassholder for den faktiske verdien som vil bli satt ved kjøretid. Før spørringen utføres, må parameteren eller parametrene stilles inn ved å utstede setParameter metode.

En interessant ting å merke seg er at de TypedQuery støtter metodekjetting som blir veldig nyttig når flere parametere må settes.

La oss fortsette og lage en variant av forrige spørring ved hjelp av to navngitte parametere for å illustrere metodekjedingen:

TypedQuery query = em.createQuery ("VELG e FRA medarbeider e WHERE e.name =: name AND e.age =: empAge", Employee.class); String empName = "John Doe"; int empAge = 55; Liste ansatte = spørring .setParameter ("navn", empName) .setParameter ("empAge", empAge) .getResultList ();

Her henter vi alle ansatte med gitt navn og alder. Som vi tydelig ser og man kan forvente, kan vi bygge spørsmål med flere parametere og så mange forekomster av dem som kreves.

Hvis vi av en eller annen grunn trenger å bruke den samme parameteren mange ganger i samme spørring, trenger vi bare å angi den en gang ved å utstede "setParameter”-Metoden. Ved kjøretid vil de angitte verdiene erstatte hver forekomst av parameteren.

Til slutt er det verdt å nevne det Java Persistence API-spesifikasjonen pålegger ikke navngitte parametere å støttes av innfødte spørsmål. Selv når noen implementeringer som Hibernate støtter det, må vi ta i betraktning at hvis vi bruker det, vil spørringen ikke være like bærbar.

4.4. Samlingsverdige navngitte parametere

For klarhetens skyld, la oss også demonstrere hvordan dette fungerer med samlingsverdiene.

TypedQuery spørring = entityManager.createQuery ("VELG e FRA ansatt e WHERE e.empNumber IN (: numbers)", Employee.class); Liste empNumbers = Arrays.asList ("A123", "A124"); Liste ansatte = query.setParameter ("numbers", empNumbers) .getResultList ();

Som vi ser, fungerer det på en lignende måte som posisjonsparametere.

5. Parametere for kriteriespørsmål

Et JPA-spørsmål kan bygges ved hjelp av JPA Criteria API, som Hibernates offisielle dokumentasjon forklarer i detalj.

I denne typen spørsmål representerer vi parametere ved å bruke objekter i stedet for navn eller indekser.

La oss bygge den samme spørringen igjen, men denne gangen bruker vi Criteria API for å demonstrere hvordan du håndterer spørringsparametere når du arbeider med Kriterier:

CriteriaBuilder cb = em.getCriteriaBuilder (); CriteriaQuery cQuery = cb.createQuery (ansatt.klasse); Rot c = cQuery.from (ansatt.klasse); ParameterExpression paramEmpNumber = cb.parameter (String.class); cQuery.select (c) .where (cb.equal (c.get (Employee_.empNumber), paramEmpNumber)); TypedQuery spørring = em.createQuery (cQuery); Streng empNumber = "A123"; query.setParameter (paramEmpNumber, empNumber); Ansatt ansatt = query.getResultList ();

For denne typen spørsmål er parametermekanikeren litt annerledes siden vi bruker et parameterobjekt, men egentlig er det ingen forskjell.

I det forrige eksemplet kan vi se bruken av Ansatt_ klasse. Vi genererte denne klassen med Dvalemodell-generatoren. Disse komponentene er en del av den statiske JPA-metamodellen, som gjør det mulig å lage kriteriespørsmål på en sterkt skrevet måte.

6. Konklusjon

I denne artikkelen har vi fokusert på mekanikken til å bygge spørsmål ved å bruke JPA-søkeparametere eller inndataparametere.

Vi har lært at vi har to typer søkeparametere, posisjonelle og navngitte. Det er opp til oss hvilken som passer best til våre mål.

Det er også verdt å merke seg at alle søkeparametere må være enkeltverdige bortsett fra i uttrykkene. Til i uttrykk, kan vi bruke innsamlingsverdige inngangsparametere, for eksempel matriser eller Listes som vist i de foregående eksemplene.

Kildekoden til denne opplæringen er som vanlig tilgjengelig på GitHub.