Java >> Java tutorial >  >> Tag >> new

JPA 2.2s nye getResultStream()-metode, og hvordan du IKKE bør bruge den

JPA 2.2 introducerede flere nye funktioner, og en af ​​dem er den nye getResultStream() metode. Denne metode er nu en del af Forespørgslen interface. Som du måske kan gætte ud fra navnet, giver det dig mulighed for at hente resultatet af din forespørgsel som en Strøm . Målet med denne metode er at give en effektiv måde at bevæge sig gennem et resultatsæt. I bedste tilfælde giver det dig mulighed for at rulle gennem resultatsættet i stedet for at hente alle poster på én gang.

Du kan se et simpelt eksempel med den nye metode her. Du kalder bare getResultStream() metoden i stedet for getResultList() metode. Resten af ​​API'et ændrede sig ikke. Så du kan oprette forespørgslen, indstille bindeparameterværdier og begrænse antallet af valgte poster på samme måde, som du gjorde i JPA 2.1.

Stream<Author> authors = em.createQuery("SELECT a FROM Author a", Author.class).getResultStream();

Én metode med forskellige implementeringer

Metoden og dens hensigt er beskrevet i JPA-specifikationen. Men implementeringen afhænger af persistensudbyderen, og du bør tjekke dokumentationen og koden, før du bruger den.

Standardimplementeringen, leveret af Query-grænsefladen, kalder bare getResultList() metode til at hente resultatsættet som en Liste og kalder stream() metode til at omdanne den til en Strøm . Denne tilgang giver ingen fordele sammenlignet med getResultList() metode tilgængelig i JPA 2.1.

Men det må forventes, at de fleste JPA-implementeringer giver deres egen implementering af getResultStream() metode. Hibernate introducerede for eksempel sin stream() metode i version 5.2, og jeg ville blive overrasket, hvis de ikke genbruger den til JPA's getResultStream() metode. Den bruger Hibernates ScrollableResult-implementering til at bevæge sig gennem resultatsættet og hente posterne i batches. Det forhindrer dig i at indlæse alle poster i resultatsættet på én gang og giver dig mulighed for at behandle dem mere effektivt.

Gør ikke dette efter at have hentet resultatsættet

Siden introduktionen af ​​Stream I Java 8 så jeg en masse eksempler på blogs og i forumindlæg. De bruges ofte til at behandle enorme mængder data. Stream API'en er designet til det, og det er en fantastisk måde at behandle data, som du læser fra en fil eller har fået dem via et API-kald.

Men vær forsigtig, hvis du har dine data fra en database. Du kan selvfølgelig bruge Stream API til at behandle udvalgte entiteter eller DTO'er. Men der er flere ting, som databasen kan meget bedre end din Java-kode. Så sørg for at distribuere behandlingstrinnene intelligent, så du bruger databasen og din virksomhed så effektivt som muligt. Her er et par ting, du bedre bør gøre i din forespørgsel og ikke via Java Stream API.

Filtrer elementerne i Strømmen

Det var et af de første eksempler, jeg så, da Java 8 introducerede Stream API. filteret metode giver dig mulighed for at vælge elementerne i Strømmen der opfylder visse kriterier. Dens implementering er nem, og for nogle Java-udviklere er det mere behageligt at implementere filterkriterierne i Java-koden i stedet for JPQL-forespørgslen. Men det er noget, du ikke bør gøre.

Databaser er optimeret til denne use case og kan gøre det meget hurtigere. Så lad være med at implementere yderligere filter, når du behandler din Strøm . Du bør bedre bruge JPQL eller Criteria API til at angive filterkriterierne i din forespørgsel. Og hvis det ikke er muligt, kan du stadig bruge en indbygget SQL-forespørgsel.

Jeg forklarede JPQL's muligheder meget detaljeret i et tidligere indlæg. Så her er blot et lille og simpelt eksempel på, hvad du kan gøre i et WHERE klausul. Du kan bruge flere sammenligningsoperatører, få adgang til attributterne for alle entiteter, der henvises til i FROM-sætningen eller implicit tilsluttet via stioperatøren, og du kan endda kalde databasefunktioner for at udløse mere komplekse operationer.

SELECT a FROM Author a WHERE a.firstName like ‘%and%’ and a.id >= 20 and size(author.books) >= 5

Begræns antallet af elementer i strømmen

Stream API'en giver flere metoder til at annullere behandlingen eller til at hente visse elementer fra strømmen. Og du kan gøre det samme i dine forespørgsler. Så hvad er den bedste tilgang?

Du bør kun vælge de databaseposter, som du ønsker at behandle i din ansøgning. Så hvis du allerede ved, at du bare har brug for et vist antal poster, bør du altid begrænse størrelsen af ​​resultatsættet i forespørgslen. Typiske eksempler er forespørgsler, der vælger den seneste post, der opfylder visse kriterier, eller som henter en liste over poster, der vil blive præsenteret i en pagineret liste i brugergrænsefladen.


Følg mig på YouTube for ikke at gå glip af nye videoer.

Grunden til at du skal gøre det i din forespørgsel er enkel. Antallet af poster, du vælger, kan påvirke udførelsesplanen for din forespørgsel, f.eks. kan indekser bruges eller ikke bruges baseret på antallet af valgte poster. Det øger eksekveringstiden for din forespørgsel. Opbygning af et større resultatsæt i databasen kræver også flere ressourcer og gør derfor din databaseserver langsommere.

Så det er bedre at bruge setFirstResult og setMaxResult metoder på Forespørgsel og TypedQuery grænseflade.

Stream<Author> authors = em.createQuery("SELECT a FROM Author a ORDER BY a.id ASC", Author.class)
                .setMaxResults(5)
                .setFirstResult(10)
                .getResultStream();

Din persistensudbyder oversætter dette til en LIMIT og OFFSET klausul i SQL SELECT-sætningen. Det fortæller databasen kun at returnere det nødvendige antal poster. Så den kan bruge de tilgængelige indekser, anvende intern optimering og udnytte sine ressourcer effektivt.

16:58:00,274 DEBUG [org.hibernate.SQL] - select author0_.id as id1_0_, author0_.firstName as firstNam2_0_, author0_.lastName as lastName3_0_, author0_.version as version4_0_ from Author author0_ order by author0_.id ASC limit ? offset ?

Sortér elementerne i Strømmen

Du kan bruge den sorterede metode leveret af Strømmen grænseflade til at sortere elementerne i din Strøm . Men det er en anden operation, som databasen kan gøre meget hurtigere end din Java-kode. Du skal blot tilføje en ORDER BY klausul til din forespørgsel, og databasen returnerer resultatsættet i din foretrukne rækkefølge.

I JPQL kan du gøre det med en lignende syntaks, som du sikkert kender fra SQL.

Stream<Author> authors = em.createQuery("SELECT a FROM Author a ORDER BY a.id ASC", Author.class).getResultStream();

Og i en CriteriaQuery , skal du angive en eller flere ordre prædikater til orderBy metode.

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(Book.class);
Root book = cq.from(Book.class);	
cq.select(book);

cq.orderBy(cb.asc(book.get("title")));

Stream books = em.createQuery(cq).getResultStream();

I begge tilfælde tilføjer persistensudbyderen en ORDER BY-klausul til SQL-forespørgslen.

17:49:02,103 DEBUG [org.hibernate.SQL] - select author0_.id as id1_0_, author0_.firstName as firstNam2_0_, author0_.lastName as lastName3_0_, author0_.version as version4_0_ from Author author0_ order by author0_.id ASC

Forespørgslen returnerer nu de valgte databaseposter i den definerede rækkefølge, og du kan bruge Stream til at gentage resultatsættet.

Oversigt

Som du har set, giver den nye getResultStream-metode dig mulighed for at hente resultatsættet som en Stream. I bedste tilfælde implementerede din persistensudbyder denne metode på en måde, der giver dig mulighed for at bevæge dig gennem resultatsættet og ikke kræver at hente alle poster på én gang.

Stream API'en giver en fantastisk måde at behandle resultatsættet på. Men husk venligst, at databaser er meget optimeret til at arbejde med enorme datasæt og kan gøre det meget hurtigere end din Java-kode. Så det er bedre at udføre alle filter-, begrænsnings- og sorteringsoperationer i databasen og bare bruge Stream til at gentage resultatsættet.


Java tag