Dvaletilstand @NotNull vs @Column (nullable = false)

1. Introduktion

Ved første øjekast, det kan virke som begge @NotNull og @Column (nullable = false) annoteringer tjener det samme formål og kan bruges om hverandre. Men som vi snart vil se, er dette ikke helt sandt.

Selvom det, når det bruges på JPA-enheden, begge forhindrer i det væsentlige opbevaring nul værdier i den underliggende database, er der betydelige forskelle mellem disse to tilgange.

I denne hurtige vejledning sammenligner vi @NotNull og @Column (nullable = false) begrænsninger.

2. Afhængigheder

For alle de præsenterede eksempler bruger vi en simpel Spring Boot-applikation.

Her er et relevant afsnit af pom.xml fil, der viser nødvendige afhængigheder:

  org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-validering com.h2database h2 

2.1. Eksempel på enhed

Lad os også definere en meget enkel enhed, som vi bruger i hele denne tutorial:

@Entity public class Element {@Id @GeneratedValue privat Lang id; privat BigDecimal pris; }

3. Den @NotNull Kommentar

Det @NotNull annotation er defineret i Bean Validation-specifikationen. Dette betyder, at dets anvendelse ikke kun er begrænset til enhederne. Tværtimod kan vi bruge @NotNull på enhver anden bønne også.

Lad os dog holde fast i vores brugssag og tilføje @NotNull kommentar til Vare'S pris Mark:

@Entity public class Element {@Id @GeneratedValue privat Lang id; @NotNull privat BigDecimal pris; }

Lad os nu prøve at fastholde et element med en nulpris:

@SpringBootTest offentlig klasse ItemIntegrationTest {@Autowired private ItemRepository itemRepository; @Test offentligt ugyldigt shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (new Item ()); }}

Og lad os se dvaleens output:

2019-11-14 12: 31: 15.070 FEJL 10980 --- [main] ohiExceptionMapperStandardImpl: HHH000346: Fejl under managed flush [Validering mislykkedes for klasser [com.baeldung.h2db.springboot.models.Item] under vedvarende tid for grupper [javax.validation.groups.Default,] Liste over overtrædelser af begrænsninger: [ConstraintViolationImpl {interpolatedMessage = 'må ikke være nul', propertyPath = pris, rootBeanClass = klasse com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]] (...) Forårsaget af: javax.validation.ConstraintViolationException: Validering mislykkedes for klasser [com.baeldung.h2db.springboot.models.Item] under vedvarende tid for grupper [javax.validation.groups.Default,] Liste over begrænsninger med begrænsning: [ConstraintViolationImpl {interpolatedMessage = 'må ikke være nul', propertyPath = pris, rootBeanClass = klasse com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]

Som vi kan se, i dette tilfælde kastede vores system javax.validation.ConstraintViolationException.

Det er vigtigt at bemærke, at dvale ikke udløste SQL-insert-sætningen. Derfor blev ugyldige data ikke gemt i databasen.

Dette skyldes, at den præ-persistente enheds livscyklushændelse udløste bønnevalidering lige før forespørgslen blev sendt til databasen.

3.1. Skema generation

I det foregående afsnit har vi præsenteret, hvordan @NotNull validering fungerer.

Lad os nu finde ud af, hvad der sker, hvis vi lad dvale generere databaseskemaet for os.

Af den grund sætter vi et par ejendomme i vores application.properties fil:

spring.jpa.hibernate.ddl-auto = create-drop spring.jpa.show-sql = true

Hvis vi nu starter vores ansøgning, ser vi DDL-erklæringen:

Opret tabelelement (id bigint ikke null, pris decimal (19,2) ikke null, primær nøgle (id))

Overraskende nok Dvaletilstand tilføjer automatisk ikke null begrænsning til pris søjledefinition.

Hvordan er det muligt?

Det viser sig, ud af boksen oversætter Dvaletilstand de bønnevalideringsanmærkninger, der er anvendt på enhederne, til DDL-skema-metadata.

Dette er ret praktisk og giver meget mening. Hvis vi ansøger @NotNull til enheden, vil vi sandsynligvis lave den tilsvarende databasekolonne ikke null såvel.

Men hvis vi af en eller anden grund ønsker det for at deaktivere denne dvale-funktion er alt, hvad vi skal gøre, at indstille hibernate.validator.apply_to_ddl ejendom til falsk.

Lad os opdatere vores for at teste dette application.properties:

spring.jpa.hibernate.ddl-auto = create-drop spring.jpa.show-sql = true spring.jpa.properties.hibernate.validator.apply_to_ddl = false

Lad os køre applikationen og se DDL-erklæringen:

Opret tabelelement (id bigint ikke null, pris decimal (19,2), primær nøgle (id))

Som forventet, denne gang tilføjede dvale ikke ikke null begrænsning til pris kolonne.

4. Den @Column (nullable = false) Kommentar

Det @Kolonne annotation er defineret som en del af Java Persistence API-specifikationen.

Det bruges hovedsageligt i DDL-skemaets metadata-generation. Det betyder at hvis vi lader dvale automatisk generere databaseskemaet, anvender det ikke null begrænsning til den bestemte databasekolonne.

Lad os opdatere vores Vare enhed med @Column (nullable = false) og se hvordan dette fungerer i aktion:

@Entity public class Element {@Id @GeneratedValue private Lang id; @Column (nullable = false) privat BigDecimal pris; }

Vi kan nu forsøge at fortsætte a null pris værdi:

@SpringBootTest offentlig klasse ItemIntegrationTest {@Autowired private ItemRepository itemRepository; @Test offentligt ugyldigt shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (new Item ()); }}

Her er uddraget af dvaleens output:

Dvaletilstand: Opret tabelelement (id bigint ikke nul, pris decimal (19,2) ikke nul, primær nøgle (id)) (...) Dvaletilstand: indsæt i vare (pris, id) værdier (?,?) 2019- 11-14 13: 23: 03.000 WARN 14580 --- [main] ohengine.jdbc.spi.SqlExceptionHelper: SQL Error: 23502, SQLState: 23502 2019-11-14 13: 23: 03.000 FEJL 14580 --- [main ] ohengine.jdbc.spi.SqlExceptionHelper: NULL ikke tilladt for kolonne "PRICE"

Først og fremmest kan vi bemærke det Dvaletilstand genererede priskolonnen med ikke null begrænsning som vi forventede.

Derudover var det i stand til at oprette SQL-insert-forespørgslen og videregive den. Som resultat, det er den underliggende database, der udløste fejlen.

4.1. Validering

Næsten alle kilder understreger det @Column (nullable = false) bruges kun til skema DDL generation.

Dvale er dog i stand til udføre validering af enheden mod det mulige nul værdier, selvom det tilsvarende felt kun er kommenteret med @Column (nullable = false).

For at aktivere denne dvale-funktion skal vi udtrykkeligt indstille hibernate.check_nullability ejendom til rigtigt:

spring.jpa.show-sql = true spring.jpa.properties.hibernate.check_nullability = true

Lad os nu udføre vores testsag igen og undersøge output:

org.springframework.dao.DataIntegrityViolationException: ikke-null egenskab refererer til en nul eller forbigående værdi: com.baeldung.h2db.springboot.models.Item.price; nestet undtagelse er org.hibernate.PropertyValueException: ejendom-ejendom refererer til en nul eller forbigående værdi: com.baeldung.h2db.springboot.models.Item.price

Denne gang kastede vores test sag org.hibernate.PropertyValueException.

Det er afgørende at bemærke, at i dette tilfælde Dvaletilstand sendte ikke indsæt SQL-forespørgslen til databasen.

5. Resume

I denne artikel har vi beskrevet, hvordan @NotNull og @Column (nullable - false) annoteringer fungerer.

Selvom de begge forhindrer os i at opbevare nul værdier i databasen, tager de forskellige tilgange.

Som en tommelfingerregel, vi foretrækker @NotNull kommentar over @Column (nullable = false) kommentar. På denne måde sørger vi for, at valideringen finder sted, inden Hibernate sender nogen indsæt eller opdater SQL-forespørgsler til databasen.

Det er det normalt også bedre at stole på standardreglerne defineret i Bean Validation, snarere end at lade databasen håndtere valideringslogikken.

Men selvom vi lader dvale generere databaseskemaet, det oversætter @NotNull kommentar til databasebegrænsningerne. Det skal vi kun sørge for hibernate.validator.apply_to_ddl ejendom er indstillet til rigtigt.

Som sædvanligt er alle kodeeksempler tilgængelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found