Hibernate @NotNull vs @Column (nullable = false)

1. Introduksjon

Ved første øyekast, det kan virke som begge @Ikke null og @Column (nullable = false) merknader tjener samme formål og kan brukes om hverandre. Men som vi snart vil se, er dette ikke helt sant.

Selv om det brukes på JPA-enheten, begge forhindrer i hovedsak lagring null verdier i den underliggende databasen, er det signifikante forskjeller mellom disse to tilnærmingene.

I denne raske opplæringen vil vi sammenligne @Ikke null og @Column (nullable = false) begrensninger.

2. Avhengigheter

For alle de presenterte eksemplene, bruker vi en enkel Spring Boot-applikasjon.

Her er en relevant del av pom.xml fil som viser nødvendige avhengigheter:

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

2.1. Eksempel på enhet

La oss også definere en veldig enkel enhet som vi skal bruke gjennom denne opplæringen:

@Entity public class Item {@Id @GeneratedValue private Long id; privat BigDecimal pris; }

3. Den @Ikke null Kommentar

De @Ikke null merknader er definert i spesifikasjonen Bean Validation. Dette betyr at bruken ikke bare er begrenset til enhetene. Tvert imot, vi kan bruke @Ikke null på andre bønner også.

La oss holde oss til brukssaken vår og legge til @Ikke null kommentar til Punkt‘S pris felt:

@Entity public class Item {@Id @GeneratedValue private Long id; @NotNull privat BigDecimal-pris; }

La oss nå prøve å vedvare et element med en nullpris:

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

Og la oss se Hibernates produksjon:

2019-11-14 12: 31: 15.070 FEIL 10980 --- [hoved] ohiExceptionMapperStandardImpl: HHH000346: Feil under administrert spyling [Validering mislyktes for klasser [com.baeldung.h2db.springboot.models.Item] under vedvarende tid for grupper [javax.validation.groups.Default,] Liste over begrensningsbrudd: [ConstraintViolationImpl {interpolatedMessage = 'may not be null', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]] (...) Forårsaket av: javax.validation.ConstraintViolationException: Validering mislyktes for klasser [com.baeldung.h2db.springboot.models.Item] under vedvarende tid for grupper [javax.validation.groups.Default,] Liste over begrensningsbrudd: [ConstraintViolationImpl {interpolatedMessage = 'may not be null', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]

Som vi kan se, i dette tilfellet kastet systemet vårt javax.validation.ConstraintViolationException.

Det er viktig å legge merke til at dvalemodus ikke utløste SQL insert-setningen. Følgelig ble ugyldige data ikke lagret i databasen.

Dette er fordi den forvarende livssyklushendelsen til enheten utløste bønnevalidering like før du sendte spørringen til databasen.

3.1. Skjema generasjon

I forrige avsnitt har vi presentert hvordan @Ikke null validering fungerer.

La oss nå finne ut hva som skjer hvis vi la dvalemodus generere databaseskjemaet for oss.

Av den grunn setter vi et par eiendommer i vårt application.properties fil:

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

Hvis vi nå starter søknaden vår, ser vi DDL-uttalelsen:

opprett tabellelement (id bigint ikke null, pris desimal (19,2) ikke null, primærnøkkel (id))

Overraskende, Dvalemodus legger automatisk til ikke null begrensning for pris kolonnedefinisjon.

Hvordan er det mulig?

Som det viser seg, ut av boksen, oversetter dvalemodus kommentarene for bønnevalidering som er brukt på enhetene til metadata for DDL-skjema.

Dette er ganske praktisk og gir mye mening. Hvis vi søker @Ikke null til enheten, vil vi mest sannsynlig lage den tilsvarende databasekolonnen ikke null også.

Men hvis vi av en eller annen grunn vil for å deaktivere denne dvalemodus-funksjonen, er alt vi trenger å gjøre dvalemodus.validator.apply_to_ddl eiendom til falsk.

For å teste dette, la oss oppdatere vår application.properties:

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

La oss kjøre applikasjonen og se DDL-setningen:

lag tabellelement (id bigint ikke null, desimalpris (19,2), primærnøkkel (id))

Som forventet, denne gangen la ikke dvalemodus til ikke null begrensning for pris kolonne.

4. Den @Column (nullable = false) Kommentar

De @Kolonne merknader er definert som en del av Java Persistence API-spesifikasjonen.

Den brukes hovedsakelig i DDL-skjemaets metadata generasjon. Dette betyr at Hvis vi lar dvalemodus generere databaseskjemaet automatisk, bruker den ikke null begrensning til den spesifikke databasekolonnen.

La oss oppdatere vår Punkt enhet med @Column (nullable = false) og se hvordan dette fungerer i aksjon:

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

Vi kan nå prøve å vedvare a null pris verdi:

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

Her er utdraget av dvalemodusens utgang:

Dvalemodus: opprett tabellelement (id bigint ikke null, pris desimal (19,2) ikke null, primærnøkkel (id)) (...) Dvalemodus: sett inn i vareverdiene (pris, id) (?,?) 2019- 11-14 13: 23: 03.000 ADVARSEL 14580 --- [main] ohengine.jdbc.spi.SqlExceptionHelper: SQL Error: 23502, SQLState: 23502 2019-11-14 13: 23: 03.000 FEIL 14580 --- [main ] ohengine.jdbc.spi.SqlExceptionHelper: NULL ikke tillatt for kolonnen "PRICE"

Først av alt kan vi merke det Dvalemodus genererte priskolonnen med ikke null begrensning som vi forventet.

I tillegg var det i stand til å opprette SQL-innsettingsspørringen og sende den gjennom. Som et resultat, det er den underliggende databasen som utløste feilen.

4.1. Validering

Nesten alle kildene understreker det @Column (nullable = false) brukes bare til skjema DDL-generering.

Dvalemodus er imidlertid i stand til det utføre validering av enheten mot det mulige null verdier, selv om det tilsvarende feltet bare er merket med @Column (nullable = false).

For å aktivere denne dvalemodus-funksjonen, må vi angi hibernate.check_nullability eiendom til ekte:

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

La oss nå utføre testsaken vår igjen og undersøke utdataene:

org.springframework.dao.DataIntegrityViolationException: ikke-null-egenskap refererer til en null eller forbigående verdi: com.baeldung.h2db.springboot.models.Item.price; nestet unntak er org.hibernate.PropertyValueException: ikke-null-egenskap refererer til en null eller forbigående verdi: com.baeldung.h2db.springboot.models.Item.price

Denne gangen kastet testsaken vår org.hibernate.PropertyValueException.

Det er viktig å legge merke til at i dette tilfellet Dvalemodus sendte ikke inn SQL-spørringen til databasen.

5. Sammendrag

I denne artikkelen har vi beskrevet hvordan @Ikke null og @Column (null - falsk) merknader fungerer.

Selv om de begge hindrer oss i å lagre null verdier i databasen, tar de forskjellige tilnærminger.

Som en tommelregel, vi bør foretrekke @Ikke null kommentar over @Column (nullable = false) kommentar. På denne måten sørger vi for at valideringen skjer før dvalemodus sender innlegg eller oppdater SQL-spørsmål til databasen.

Også er det vanligvis bedre å stole på standardreglene definert i Bean Validation, i stedet for å la databasen håndtere valideringslogikken.

Men selv om vi lar dvalemodus generere databaseskjemaet, det vil oversette @Ikke null merknader i databasebegrensningene. Vi må da bare sørge for at dvalemodus.validator.apply_to_ddl eiendommen er satt til ekte.

Som vanlig er alle kodeeksemplene tilgjengelige på GitHub.


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