Java >> Java tutorial >  >> Tag >> SQL

Gå i dvale med PostgreSQL – 6 ting, du skal vide

PostgreSQL er en af ​​de mest populære relationsdatabaser, og Hibernate er nok den mest populære JPA-implementering. Så det er ingen overraskelse, at de ofte bruges sammen, og at du ikke behøver at forvente større problemer ved at gøre det.

Men som så ofte er der forskel på "det virker" og "det virker fantastisk". Ud af boksen fungerer Hibernate og PostgreSQL godt sammen. Men hvis du vil bruge begge systemer fuldt ud, skal du vide et par ting og undgå nogle andre.

Her er min liste over de 5 vigtigste ting, du bør vide, når du vil bruge Hibernate med PostgreSQL.

1. Tilknytninger:Primære nøgler

Primære nøgler og generering af unikke værdier synes at være grundlæggende funktioner. JPA-specifikationen definerer forskellige strategier til at generere primære nøgleværdier, og du kan bruge dem alle sammen med PostgreSQL.

Men det betyder ikke, at du bare skal vælge en af ​​dem.

TABELLEN strategi bruger en databasetabel til at generere unikke primære nøgleværdier. Dette kræver pessimistisk låsning og er ikke den mest effektive tilgang.

IDENTITET strategi tvinger Hibernate til at udføre SQL INSERT-sætningen med det samme. På grund af dette kan Hibernate ikke bruge nogen af ​​sine præstationsoptimeringsstrategier, der kræver en forsinket udførelse af erklæringen. Et eksempel på det er JDBC batching. Men det kan også påvirke simple ting, som f.eks. at opdatere en attribut, før entiteten bliver ved. Når Hibernate skal udføre INSERT-sætningen med det samme, skal den udføre en ekstra UPDATE-sætning for at bevare den ændrede værdi i stedet for at bruge denne værdi i INSERT-sætningen.


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

Den bedste generationsstrategi, du kan bruge med en PostgreSQL-database, er SEQUENCE strategi. Den bruger en simpel databasesekvens og er meget optimeret af PostgreSQL. Og Hibernate bruger som standard en optimeret algoritme for at undgå unødvendige SELECT-sætninger.

Hvis du vil bruge Hibernates standardsekvens, skal du blot tilføje en @GeneratedValue annotation til din primære nøgleattribut og indstil strategien til GenerationType.SEQUENCE.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

Eller du kan oprette en brugerdefineret sekvens med følgende sætning.

CREATE SEQUENCE book_seq;

Du kan derefter henvise til det i en @SequenceGenerator annotation.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_generator")
@SequenceGenerator(name="book_generator", sequenceName = "book_seq", allocationSize=50)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

2. Tilknytninger:Tilpassede datatyper, såsom JSONB

PostgreSQL understøtter en sat proprietær datatype, som Hibernate ikke kortlægger som standard. Populære eksempler på det er JSON- og JSONB-datatyperne, som giver dig mulighed for at fortsætte og forespørge på JSON-dokumenter i en PostgreSQL-database.

Hvis du vil bruge disse typer med Hibernate, skal du selv definere kortlægningen. Det kræver ekstra kode, men det er ikke så kompliceret, som det måske lyder. Du skal blot implementere og registrere en UserType som fortæller Hibernate, hvordan Java-objektet skal kortlægges til en understøttet JDBC-type og omvendt.

Jeg forklarede den påkrævede implementering meget detaljeret i Sådan bruger du PostgreSQLs JSONB-datatype med Hibernate. Du kan bruge den samme tilgang til at implementere en tilpasset kortlægning for alle PostgreSQL-typer, der ikke understøttes af Hibernate.

3. Kortlægninger:Skrivebeskyttede visninger


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

Fra et kortlægningssynspunkt er databasetabeller og visninger ret ens, og du kan kortlægge dem begge til en enhedsklasse. Den eneste forskel er, at nogle visninger er skrivebeskyttede. Og det er en god praksis at kortlægge dem til en skrivebeskyttet enhed.

Som standard understøtter Hibernate læse- og skrivehandlinger for alle enheder. Hvis du vil gøre en enhed skrivebeskyttet, skal du fortælle Hibernate, at den er uforanderlig. Du kan gøre det ved at annotere enhedsklassen med en @Immutable annotation.

@Entity
@Immutable
public class BookView {
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "id", updatable = false, nullable = false)
	private Long id;
	@Version
	@Column(name = "version")
	private int version;

	@Column
	private String title;

	@Column
	@Temporal(TemporalType.DATE)
	private Date publishingDate;

	@Column
	private String authors;
	
	...
	
}

4. Forespørgsler:Brug PostgreSQL-specifikke forespørgselsfunktioner


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

Når du er fortrolig med JPQL og SQL, ved du allerede, at JPQL kun understøtter en lille delmængde af SQL-standarden. Men det er ikke et reelt problem, for hvis JPQL ikke er kraftfuld nok til at implementere dine use cases, kan du bruge en indbygget SQL-forespørgsel i stedet.

Native SQL-forespørgsler giver dig mulighed for at bruge det fulde SQL-funktionssæt inklusive alle databasespecifikke forespørgselsfunktioner. Du opretter dem på samme måde som dine JPQL-forespørgsler. Du kan definere en navngivet indbygget forespørgsel med en @NamedNativeQuery annotering eller opret en indbygget ad hoc-forespørgsel ved at kalde createNativeQuery metode på EntityManager .

@NamedNativeQuery(name = "selectAuthorNames", query = "SELECT a.firstname, a.lastname FROM Author a")
Query q = em.createNativeQuery("SELECT a.firstname, a.lastname FROM Author a");
List<Object[]> authors = q.getResultList();

for (Object[] a : authors) {
    System.out.println("Author "
            + a[0]
            + " "
            + a[1]);
}

5. Forespørgsler:Kald PostgreSQL-specifikke SQL-funktioner

Du kan selvfølgelig bruge en indbygget SQL-forespørgsel til at kalde en PostgreSQL-specifik SQL-funktion på samme måde som enhver anden proprietær forespørgselsfunktion. Men siden JPA 2.1 kan du også kalde disse funktioner i dine JPQL-forespørgsler.

JPQL-funktionen funktion giver dig mulighed for at kalde enhver SQL-funktion, der understøttes af din database. Du skal blot angive navnet på funktionen som den første parameter, efterfulgt af en valgfri liste over parametre, der vil blive brugt til at kalde SQL-funktionen.

Følgende kodestykke viser et simpelt eksempel, der kalder SQL-funktionen beregn med parametrene 1 og 2 .

Author a = em.createQuery("SELECT a FROM Author a WHERE a.id = function('calculate', 1, 2)", Author.class).getSingleResult();

6. Forespørgsler:Call Stored Procedures

PostgreSQL skelner ikke mellem funktioner og lagrede procedurer. Det understøtter kun meget fleksible funktioner, som kan bruges som lagrede procedurer eller som SQL-funktioner. Jeg har allerede vist dig, hvordan du kalder en ikke-standard SQL-funktion. Så lad os tage et kig på de lagrede procedurer.

Når din PostgreSQL-funktion returnerer en REF_CURSOR parameter, som er en markør på et resultatsæt, skal du kalde det som en lagret procedure. Følgende kodestykke viser et eksempel på en sådan funktion.

CREATE OR REPLACE FUNCTION get_reviews(bookid bigint)
  RETURNS refcursor AS
$BODY$
    DECLARE
      reviews refcursor;           – Declare cursor variables                         
    BEGIN
      OPEN reviews FOR SELECT id, comment, rating, version, book_id FROM review WHERE book_id = bookId;
      RETURN reviews;
    END;
  $BODY$
  LANGUAGE plpgsql

Siden JPA 2.1 kan du kalde en lagret procedure med en @NamedStoredProcedureQuery eller en ad-hoc StoredProcedureQuery .

@NamedStoredProcedureQuery


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

Med en @NamedStoredProcedureQuery annotation kan du definere et funktionskald, som du kan bruge i din virksomhedskode. Følgende kodestykke definerer et kald af get_reviews fungere. Det fortæller Hibernate at give en inputparameter af typen Lang og forvente en REF_CURSOR som resultat. resultClass parameter fortæller Hibernate at kortlægge alle poster i REF_CURSOR for at gennemgå genstande.

@NamedStoredProcedureQuery(
	name = "getReviews", 
	procedureName = "get_reviews", 
	resultClasses = Review.class, 
	parameters = {
		@StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class), 
		@StoredProcedureParameter(mode = ParameterMode.IN, type = Long.class)
	}
)

Du kan ringe til @NamedStoredProcedureQuery på samme måde, som du ville kalde en @NamedQuery . Du skal bare kalde createNamedStoredProcedureQuery metode til at instansiere forespørgslen, indstille inputparametrene og hente resultatet.

StoredProcedureQuery q = this.em.createNamedStoredProcedureQuery("getReviews");
q.setParameter(2, b.getId());
List<Review> reviews = q.getResultList();

Ad-hoc StoredProcedureQuery

Når du vil definere funktionskaldet programmatisk, kan du gøre det med en ad-hoc-forespørgsel. Det følger samme koncept som definitionen og udførelsen af ​​en @NamedStoredProcedureQuery .

Du skal først kalde createStoredProcedureQuery metoden for EntityManager med navnet på databasefunktionen og dens returtype for at instansiere en StoredProcedureQuery . I det næste trin skal du registrere alle funktionsparametre. Du kan gøre det ved at kalde registerStoredProcedureParameter metoden for StoredProcedureQuery for hver parameter.

Når du har defineret funktionskaldet, skal du blot angive værdierne for alle inputparametre og udføre forespørgslen ved at kalde getResultList metode på StoredProcedureQuery .

StoredProcedureQuery query = this.em.createStoredProcedureQuery("get_reviews", Review.class);
query.registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR);
query.registerStoredProcedureParameter(2, Long.class, ParameterMode.IN);

query.setParameter(2, b.getId());
List<Review> reviews = query.getResultList();

Oversigt

Ud af boksen fungerer Hibernate ret godt med PostgreSQL-databaser. Men som du har set, er der et par ting, du bør vide, hvis du vil bruge alle databasefunktioner og undgå ydeevneproblemer.

Især generering af unikke primære nøgleværdier er en almindelig faldgrube. Men også ting, som at kortlægge en skrivebeskyttet databasevisning eller kalde en PostgreSQL-funktion, kan være ret nyttige til de fleste projekter.


Java tag