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

5 ting, du skal vide, når du bruger Hibernate med Mysql

En af fordelene ved at bruge JPA og Hibernate er, at det giver en abstraktion af databasespecifikke dialekter og funktioner. Så i teorien kan du implementere en applikation, forbinde den til en af ​​de understøttede databaser, og den vil køre uden nogen kodeændringer.

Hibernate gør det rigtig godt. Men lad os være ærlige, du havde ikke forventet, at din applikation ville køre perfekt med alle understøttede databaser, vel?

Hibernate håndterer de vigtigste ting. Men hvis du ønsker, at din applikation skal fungere godt, skal du stadig vide, hvilke database(r) du vil bruge og justere din konfiguration og kode i overensstemmelse hermed.

I et af de tidligere indlæg talte jeg om 6 ting, du skal vide, hvis du vil bruge Hibernate med en PostgreSQL-database. Og i dag vil jeg se nærmere på MySQL-databasen.

1. Tilknytninger:Primære nøgler

Den effektive håndtering og oprettelse af primære nøgler er en grundlæggende, men en af ​​de vigtigste dele af en applikation.

@GeneratedValue annotering af JPA-specifikationen giver dig mulighed for at definere den strategi, du vil bruge til at skabe unikke primære nøgleværdier. Du kan vælge mellem SEQUENCE , IDENTITET , TABLE og AUTO .

Generelt anbefaler jeg at bruge SEQUENCE strategi, fordi den tillader Hibernate at bruge JDBC-batching og andre optimeringsstrategier, der kræver forsinket udførelse af SQL INSERT-sætninger.

Men du kan ikke bruge denne strategi med en MySQL-database. Det kræver en databasesekvens, og MySQL understøtter ikke denne funktion.

Så du skal vælge mellem IDENTITET og TABEL . Det er en nem beslutning i betragtning af problemerne med ydeevne og skalerbarhed i TABELLEN strategi.

Hvis du arbejder med en MySQL-database, bør du altid bruge GenerationType.IDENTITY . Det bruger en autoinkrementeret databasekolonne og er den mest effektive tilgang til rådighed. Du kan gøre det ved at annotere din primære nøgleattribut med @GeneratedValue(strategy =GenerationType.IDENTITY) .

@Entity
public class Author {

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

	...
}

2. Tilknytninger:Problemer med GenerationType.AUTO i Hibernate 5

Når du bruger GenerationType.AUTO, vælger Hibernate generationsstrategien baseret på Hibernate-dialekten. Det er en almindelig tilgang, hvis du skal understøtte flere databaser.

@Entity
public class Author {

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

	...
}

I ældre versioner valgte Hibernate GenerationType.IDENTITY til MySQL-databaser. Det var et godt valg. Som forklaret tidligere, er det den mest effektive tilgang til rådighed.

Men det ændrede sig i Hibernate 5. Den vælger nu GenerationType.TABLE som bruger en databasetabel til at generere primærnøgler. Denne tilgang kræver en masse databaseforespørgsler og pessimistiske låse for at generere unikke værdier.

14:35:50,959 DEBUG [org.hibernate.SQL] - select next_val as id_val from hibernate_sequence for update
14:35:50,976 DEBUG [org.hibernate.SQL] - update hibernate_sequence set next_val= ? where next_val=?
14:35:51,097 DEBUG [org.hibernate.SQL] - insert into Author (firstName, lastName, version, id) values (?, ?, ?, ?)

Du kan undgå det ved at definere en @GenericGenerator som fortæller Hibernate at bruge native strategi til at generere de primære nøgleværdier.

@Entity
public class Author {

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

	...
}

Hibernate vil derefter bruge MySQL's autoinkrementerede databasekolonne til at generere de primære nøgleværdier.

14:41:34,255 DEBUG [org.hibernate.SQL] - insert into Author (firstName, lastName, version) values (?, ?, ?)
14:41:34,298 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 1

3. Kortlægninger:Skrivebeskyttede visninger

Med JPA og Hibernate kan du kortlægge visninger på samme måde som enhver databasetabel. Så længe du følger Hibernates navnekonventioner, skal du blot implementere en klasse med en attribut for hver kolonne, du vil kortlægge og annotere den med en @Entity annotation.

Hvis visningen er skrivebeskyttet, bør du fortælle Hibernate om det med en @Immutable anmærkning. Det vil derefter ignorere alle ændringer af denne enhed.

@Entity
@Immutable
public class BookView {
  
  @Id
  @Column(name = "id", updatable = false, nullable = false)
  private Long id;

  @Column(name = "version")
  private int version;
 
  @Column
  private String title;
 
  @Column
  @Temporal(TemporalType.DATE)
  private Date publishingDate;
 
  @Column
  private String authors;
  
  ...
  
}

4. Forespørgsler:MySQL-specifikke funktioner og datatyper

Som alle andre databaser udvider MySQL SQL-standarden med et sæt brugerdefinerede funktioner og datatyper. Eksempler på det er JSON-datatypen og sysdate-funktionen.

Disse understøttes ikke af JPA, men takket være Hibernates MySQL-dialekt kan du bruge dem alligevel.

Query q = em.createQuery("SELECT a, sysdate() FROM Author a ");
List<Object[]> results = q.getResultList();

Hvis du finder en funktion eller datatype, der ikke understøttes af Hibernates MySQL-dialekt, kan du bruge en AttributeConverter til at konvertere datatypen til en understøttet og JPQL-funktionen funktion at kalde enhver funktion i en JPQL-forespørgsel.

Men husk på, at ved at bruge databasespecifikke funktioner eller datatyper binder du din applikation til en bestemt database. Du bliver nødt til at ændre disse dele af din applikation, hvis du skal understøtte en anden database.

5. Forespørgsler:Lagrede procedurer

De fleste databaseadministratorer kan lide at bruge lagrede procedurer til at udføre datatunge operationer i databasen. I de fleste tilfælde er denne tilgang meget hurtigere end at udføre de samme handlinger i Java-koden.

Men ikke desto mindre ønsker de fleste Java-udviklere ikke at bruge lagrede procedurer. Der er selvfølgelig argumentet om, at forretningslogikken bliver fordelt over flere systemer, hvilket gør det sværere at teste og forstå. En anden er, at før JPA 2.1, gav specifikationen ikke direkte støtte til lagrede procedurekald. Du skulle bruge native forespørgsler, og den overordnede tilgang føltes kompliceret.

Det ændrede sig med JPA 2.1 og introduktionen af ​​StoredProcedureQuery og @NamedStoredProcedureQuery .

@NamedStoredProcedureQuery

@NamedStoredProcedureQuery annotation giver dig mulighed for at definere det lagrede procedurekald én gang og henvise til det ved dets navn i din forretningskode. Følgende kodestykke viser et simpelt eksempel, der definerer kaldet til den lagrede procedure beregn med inputparametrene x og y og outputparameteren sum .

@NamedStoredProcedureQuery(
	name = "calculate", 
	procedureName = "calculate", 
	parameters = {	@StoredProcedureParameter(mode = ParameterMode.IN, type = Double.class, name = "x"),
			@StoredProcedureParameter(mode = ParameterMode.IN, type = Double.class, name = "y"),
			@StoredProcedureParameter(mode = ParameterMode.OUT, type = Double.class, name = "sum") })

Du kan derefter angive navnet på din @NamedStoredProcedureQuery til createNamedStoredProcedureQuery af EntityManager for at instansiere en ny StoredProcedureQuery .

StoredProcedureQuery query = em.createNamedStoredProcedureQuery("calculate");
query.setParameter("x", 1.23d);
query.setParameter("y", 4d);
query.execute();
Double sum = (Double) query.getOutputParameterValue("sum");

Som du kan se i kodestykket, kan du indstille værdien af ​​inputparametrene på samme måde, som du angiver eventuelle bindparameterværdier for en JPQL-forespørgsel. Du skal bare kalde setParameter metode på StoredProcedureQuery med navnet og værdien af ​​input-parameteren.

StoredProcedureQuery

Den programmatiske definition af et lagret procedurekald minder meget om den annotationsbaserede tilgang, jeg viste dig i det foregående eksempel. Du skal bare ringe til createStoredProcedureQueryEntityManager med navnet på den lagrede procedure, du vil udføre. Dette giver dig en StoredProcedureQuery interface, som du kan bruge til at registrere input- og outputparametrene for proceduren.

StoredProcedureQuery query = em.createStoredProcedureQuery("calculate");
query.registerStoredProcedureParameter("x", Double.class, ParameterMode.IN);
query.registerStoredProcedureParameter("y", Double.class, ParameterMode.IN);
query.registerStoredProcedureParameter("sum", Double.class, ParameterMode.OUT);

Det er alt hvad du skal gøre for at definere det lagrede procedurekald. Du kan derefter bruge det på samme måde som @NamedStoredProcedureQuery . Du indstiller først inputparameterværdierne, før du udfører det gemte procedurekald.

query.setParameter("x", 1.23d);
query.setParameter("y", 4d);
query.execute();

Oversigt

Som du har set, understøtter Hibernate allerede de fleste af de MySQL-specifikke funktioner. Men der er stadig et par ting, du skal huske på, hvis du vil oprette en bærbar og velfungerende applikation.

Især genereringen af ​​unikke primære nøgleværdier og den ændrede adfærd for GenerationType.AUTO i Hibernate 5 kan skabe uventede problemer med skalerbarheden, når du implementerer din applikation til produktion.


Java tag