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

5 nye funktioner i Hibernate 5 bør enhver udvikler kende

Hibernate-teamet udgav den første Hibernate 5-udgivelse for et stykke tid siden, og siden da introducerede de en masse nye funktioner. Jeg forklarede flere af dem her på bloggen, og det er ved at være tid til at se på de mest populære. Baseret på den søgetrafik, jeg får fra google og min personlige erfaring, er Java 8-understøttelsen den mest populære ændring. Men der er også nogle andre funktioner, som kan virke små, men som gør almindelige udviklingsopgaver en smule lettere.

Support klasser af Date and Time API som BasicTypes

Den nye Date and Time API var en af ​​de mest forventede ændringer i Java 8. Den gamle java.util.Date har en masse problemer, som endelig blev løst.

Desværre giver JPA 2.1 og Hibernate 4 ikke direkte support til det. Men det er ikke et stort problem. Det kræver blot et par linjer kode at implementere en AttributeConverter, der kortlægger en LocalDate.

Men åbenbart, den eksplicitte støtte som en BasicType er stadig meget bedre. Hibernate implementerede det i version 5.0. Siden da har du ikke brug for yderligere anmærkninger eller konverter for at bevare klasserne i Date and Time API. Du kan bruge dem på samme måde som alle andre understøttede attributtyper.

@Entity
public class Book {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = “id”, updatable = false, nullable = false)
	private Long id;
	
	private LocalDate publishingDate;

	…
}

Når du fortsætter med denne bog enhed, kortlægger Hibernate automatisk LocalDate til en JDBC DATE og bevarer det i databasen. Jeg kommer ind på flere detaljer om kortlægningen af ​​de forskellige Date and Time API-klasser i:Sådan fortsætter du LocalDateTime &Co med Hibernate 5

16:15:33,545 DEBUG [org.hibernate.SQL] – insert into Book (price, publishingDate, title, version, id) values (?, ?, ?, ?, ?)
16:15:33,550 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] – binding parameter [1] as [DOUBLE] – [null]
16:15:33,551 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] – binding parameter [2] as [DATE] – [2017-04-04]
16:15:33,552 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] – binding parameter [3] as [VARCHAR] – [Hibernate Tips]
16:15:33,553 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] – binding parameter [4] as [INTEGER] – [0]
16:15:33,554 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] – binding parameter [5] as [BIGINT] – [1]

Få forespørgselsresultater som en Strøm

Introduktion af en ny metode til at give dig dit forespørgselsresultat som en Strøm lyder ikke som en stor ting. Men strømmen metode til Hibernates Forespørgsel interface giver en ekstra fordel, der gør det særligt interessant for store resultatsæt. Den henter resultatsættet i flere batches og bruger Hibernates ScrollableResults implementering for at rulle igennem det. Denne tilgang passer godt, hvis du bruger en Strøm at behandle resultatsættets poster én efter én og hjælper dig med at implementere din use case effektivt.

Du kan bruge den nye metode siden Hibernate 5.2 for at få dine forespørgselsresultater. Følgende kodestykke viser et simpelt eksempel, der vælger alle Bog enheder fra databasen og behandler dem som en Strøm .

Stream<Object[]> books = session.createNativeQuery("SELECT b.title, b.publishingDate FROM book b").stream();
books.map(b -> new BookValue((String)b[0], (Date)b[1]))
	.map(b -> b.getTitle() + " was published on " + b.getPublishingDate())
	.forEach(m -> log.info(m));

Du kan læse mere om Hibernates stream-metode i Sådan får du forespørgselsresultater som en stream med Hibernate 5.2.

Hent flere enheder ved deres primære nøgle

Henter flere enheder efter deres ID er en meget almindelig anvendelse. De fleste udviklere implementerer det enten med en loop, der kalder find metoden for EntityManager for hver primær nøgle eller med en JPQL-forespørgsel, der kontrollerer alle primærnøgleværdier i en IN klausul. Den første mulighed kræver, at Hibernate udfører en databaseforespørgsel for hver primærnøgle. Det kan skabe enorme præstationsproblemer. Den anden giver dig mulighed for at hente alle enheder med én forespørgsel og er naturligvis den bedre mulighed.

Hibernate 5.1 introducerede en tredje mulighed, der undgår problemerne med den første og er lettere at bruge end den anden. Den nye MultiIdentifierLoadAccess interface giver en behagelig mulighed for at indlæse flere entiteter med en forespørgsel. Du skal bare kalde byMultipleIds metode på dvale session for at få en MultiIdentifierLoadAccess interface og giv en liste over primære nøgleværdier til multiLoad metode.

MultiIdentifierLoadAccess<Book> multi = session.byMultipleIds(Book.class);
List<Book> books = multi.multiLoad(1L, 2L, 3L);

Som du kan se i logoutputtet, opretter Hibernate kun 1 forespørgsel for at vælge de 3 poster fra databasen. Det er den samme forespørgsel, som du selv ville implementere, men API'en er meget nemmere at bruge.

05:44:33,872 DEBUG [org.hibernate.SQL] - 
    select
        book0_.id as id1_0_0_,
        book0_.publishingDate as publishi2_0_0_,
        book0_.title as title3_0_0_,
        book0_.version as version4_0_0_ 
    from
        Book book0_ 
    where
        book0_.id in (
            ?,?,?
        )

Hibernates implementering giver også en ekstra fordel:Den opdeler enorme lister over primære nøgleværdier i flere batches. Dette er nogle gange nødvendigt, fordi nogle databaser begrænser antallet af elementer i en IN klausul.

Jeg forklarede den nye MultiIdentifierLoadAccess grænseflade i flere detaljer i Sådan henter du flere enheder efter id med Hibernate 5.

Deltag ikke-tilknyttede enheder i en forespørgsel

Du kan nemt tilslutte tilknyttede tilknytninger mellem enheder i JPQL-forespørgsler. Kortlægningen giver allerede de påkrævede tilslutningsbetingelser, og du behøver ikke at angive dem i din forespørgsel.

Men hvad med enheder, der kortlægger tilknyttede databasetabeller, men som ikke har nogen tilknyttet tilknytning?

Og det er ikke et retorisk spørgsmål.

De fleste enhedsmodeller kortlægger ikke alle mulige associationer. De kortlægger kun dem, der synes at give værdi i domænemodellen og ikke dem, hvor 2 databasetabeller (tilsyneladende ved et uheld) gemmer den samme fremmednøgle. Det sker også ret ofte, at en til-mange forening med masser af poster på mange sider ikke bliver kortlagt med Hibernate. Risikoen for, at nogen ringer til foreningens getter og henter flere hundrede eller tusinde enheder, er bare for høj.

Det er helt fint, så længe du bare ser på domænemodellen. Du behøver sandsynligvis ikke disse associationer i modellen. Men det betyder ikke, at du ikke har brug for dem i en af ​​dine JPQL-forespørgsler.

Hvis det er tilfældet, har du 3 muligheder:

  1. Modeller tilknytningen mellem enhederne eller
  2. Brug en krydssammenføjning i din JPQL-forespørgsel, som kan skabe ydeevneproblemer eller
  3. Brug Hibernates proprietære JOIN klausul.

Jeg foretrækker mulighed 3. Det er den nemmeste og mest naturlige.

Siden Hibernate 5.1 kan du bruge en SQL-lignende syntaks til at forbinde enheder uden en modelleret tilknytning.

Query q = em.createQuery(“SELECT b.title, count(r.id) FROM Book b INNER JOIN Review r ON r.fkBook = b.id GROUP BY b.title”);
Object[] r = (Object[]) q.getSingleResult();
05:44:59,939 DEBUG [org.hibernate.SQL] - 
    select
        book0_.title as col_0_0_,
        count(review1_.id) as col_1_0_ 
    from
        Book book0_ 
    inner join
        Review review1_ 
            on (
                review1_.fkBook=book0_.id
            ) 
    group by
        book0_.title

@Repeatable anmærkninger

Gentagelige annoteringer er en af ​​de mindre ændringer i Java 8. Det giver dig mulighed for at annotere en klasse, attribut eller grænseflade med den samme annotation flere gange. Et typisk JPA-eksempel, hvor du vil gøre det, er at definere flere navngivne forespørgsler for en enhed.

Indtil videre har du været nødt til at annotere din enhed med en @NamedQueries annotation, som indeholdt et array af @NamedQuery anmærkninger. Det irriterende ved det er, at @NamedQueries annotation er kun en beholder. Det giver ikke nogen værdi i sig selv.

@Entity
@NamedQueries({
	@NamedQuery(name = “Book.findByTitle”, query = “SELECT b FROM Book b WHERE b.title = :title”),
	@NamedQuery(name = “Book.findByPublishingDate”, query = “SELECT b FROM Book b WHERE b.publishingDate = :publishingDate”)
})
public class Book implements Serializable {
	…
}

Siden Hibernate 5.2 behøver du ikke gøre det længere. I hvert fald ikke så længe du bruger Hibernates version af org.hibernate.annotations.NamedQuery anmærkning. @NamedQuery og en masse andre Hibernate-annoteringer kan nu gentages og kan tildeles flere gange. Som du kan se i det følgende kodestykke, gør det koden nemmere at læse og er meget mere behagelig at bruge.

@Entity
@NamedQuery(name = “Hibernate5Book.findByTitle”, query = “SELECT b FROM Hibernate5Book b WHERE b.title = :title”)
@NamedQuery(name = “Hibernate5Book.findByPublishingDate”, query = “SELECT b FROM Hibernate5Book b WHERE b.publishingDate = :publishingDate”)
public class Hibernate5Book implements Serializable {
	…
}

Oversigt

Hibernate 5 bragte en masse ændringer, men disse 5 var dem, som jeg bedst kan lide, og som jeg har brugt mest aktivt indtil videre. Især understøttelsen af ​​Date and Time API og den nye MultiIdentifierLoadAccess interface har været nyttige.

Hibernate introducerede åbenbart mere end blot disse 5 ændringer. Der er for eksempel en ny bootstrapping API og Sessionen interface udvider nu JPA's EntityManager . Disse ændringer er alle gode og interessante, men de har ikke haft indflydelse på mine projekter, fordi jeg arbejder i et Java EE-miljø.

Det kan være helt anderledes for dig. Så hvilke er dine yndlingsændringer i Hibernate 5? Er der nogle funktioner, du ikke vil gå glip af i dit daglige arbejde? Fortæl mig venligst om dem i kommentarerne.


Java tag