Slaapstand @NotNull vs @Column (nullable = false)

1. Inleiding

Op het eerste gezicht, het lijkt misschien dat beide @Niet nul en @Column (nullable = false) annotaties dienen hetzelfde doel en kunnen door elkaar worden gebruikt. Maar zoals we snel zullen zien, is dit niet helemaal waar.

Hoewel, wanneer gebruikt op de PPV-entiteit, beiden verhinderen in wezen opslag nul waarden in de onderliggende database, zijn er significante verschillen tussen deze twee benaderingen.

In deze korte tutorial vergelijken we de @Niet nul en @Column (nullable = false) beperkingen.

2. Afhankelijkheden

Voor alle gepresenteerde voorbeelden gebruiken we een eenvoudige Spring Boot-applicatie.

Hier is een relevant gedeelte van het pom.xml bestand dat de benodigde afhankelijkheden toont:

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

2.1. Voorbeeldentiteit

Laten we ook een heel eenvoudige entiteit definiëren die we in deze tutorial zullen gebruiken:

@Entity openbare klasse Item {@Id @GeneratedValue privé Lange id; privé BigDecimal-prijs; }

3. Het @Niet nul Annotatie

De @Niet nul annotatie wordt gedefinieerd in de Bean Validation-specificatie. Dit betekent dat het gebruik ervan niet alleen beperkt is tot de entiteiten. Integendeel, we kunnen gebruiken @Niet nul ook op een andere boon.

Laten we echter bij onze use case blijven en de @Niet nul annotatie bij de Item‘S prijs veld:

@Entity openbare klasse Item {@Id @GeneratedValue privé Lange id; @NotNull privé BigDecimal-prijs; }

Laten we nu proberen een item vast te houden met een nulprijs:

@SpringBootTest openbare klasse ItemIntegrationTest {@Autowired privé ItemRepository itemRepository; @Test openbare leegte shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (nieuw item ()); }}

En laten we de uitvoer van Hibernate bekijken:

2019-11-14 12: 31: 15.070 ERROR 10980 --- [main] ohiExceptionMapperStandardImpl: HHH000346: Fout tijdens beheerde spoeling [Validatie mislukt voor klassen [com.baeldung.h2db.springboot.models.Item] tijdens persistentie voor groepen [javax.validation.groups.Default,] Lijst met schendingen van beperkingen: [ConstraintViolationImpl {interpolatedMessage = 'mag niet null zijn', propertyPath = prijs, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]] (...) Veroorzaakt door: javax.validation.ConstraintViolationException: Validatie mislukt voor klassen [com.baeldung.h2db.springboot.models.Item] tijdens persistentie voor groepen [javax.validation.groups.Default,] Lijst met schendingen van beperkingen: [ConstraintViolationImpl {interpolatedMessage = 'mag niet null zijn', propertyPath = prijs, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]

Zoals we kunnen zien, in dit geval gooide ons systeem javax.validation.ConstraintViolationException.

Het is belangrijk op te merken dat Hibernate de SQL insert-instructie niet heeft geactiveerd. Bijgevolg werden ongeldige gegevens niet in de database opgeslagen.

Dit komt doordat de pre-persistente levenscyclusgebeurtenis van de entiteit de bean-validatie heeft geactiveerd net voordat de query naar de database werd verzonden.

3.1. Schema-generatie

In het vorige gedeelte hebben we laten zien hoe de @Niet nul validatie werkt.

Laten we nu eens kijken wat er gebeurt als we laat Hibernate het databaseschema voor ons genereren.

Om die reden zullen we een aantal eigenschappen in onze application.properties het dossier:

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

Als we nu onze applicatie starten, zien we de DDL-verklaring:

tabelitem maken (id bigint niet null, prijs decimaal (19,2) niet null, primaire sleutel (id))

Verrassend genoeg, Hibernate voegt automatisch het niet nul beperking tot de prijs kolom definitie.

Hoe is dat mogelijk?

Zoals het blijkt, uit de doos vertaalt Hibernate de bean-validatie-annotaties die op de entiteiten zijn toegepast in de metagegevens van het DDL-schema.

Dit is best handig en logisch. Als we solliciteren @Niet nul aan de entiteit willen we hoogstwaarschijnlijk de corresponderende databasekolom maken niet nul ook.

Echter, als we, om welke reden dan ook, willen om deze Hibernate-functie uit te schakelen, hoeven we alleen maar in te stellen slaapstand.validator.apply_to_ddl eigendom aan false.

Laten we, om dit te testen, onze application.properties:

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

Laten we de applicatie uitvoeren en de DDL-verklaring bekijken:

tabelitem maken (id bigint niet null, prijs decimaal (19,2), primaire sleutel (id))

Zoals verwacht, deze keer heeft Hibernate het niet nul beperking tot de prijs kolom.

4. Het @Column (nullable = false) Annotatie

De @Kolom annotatie wordt gedefinieerd als een onderdeel van de Java Persistence API-specificatie.

Het wordt voornamelijk gebruikt bij het genereren van metagegevens van het DDL-schema. Dit betekent dat als we Hibernate het databaseschema automatisch laten genereren, past het de niet nul beperking tot de specifieke databasekolom.

Laten we onze Item entiteit met de @Column (nullable = false) en kijk hoe dit in actie werkt:

@Entity openbare klasse Item {@Id @GeneratedValue privé Lange id; @Column (nullable = false) privé BigDecimal-prijs; }

We kunnen nu proberen een null prijs waarde:

@SpringBootTest openbare klasse ItemIntegrationTest {@Autowired privé ItemRepository itemRepository; @Test openbare leegte shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (nieuw item ()); }}

Hier is het fragment van de uitvoer van Hibernate:

Slaapstand: maak een tabelitem (id bigint niet nul, prijs decimaal (19,2) niet nul, primaire sleutel (id)) (...) Slaapstand: invoegen in item (prijs, id) waarden (?,?) 2019- 11-14 13: 23: 03.000 WARN 14580 --- [hoofd] ohengine.jdbc.spi.SqlExceptionHelper: SQL-fout: 23502, SQLState: 23502 2019-11-14 13: 23: 03.000 FOUT 14580 --- [hoofd ] ohengine.jdbc.spi.SqlExceptionHelper: NULL niet toegestaan ​​voor kolom "PRICE"

Dat merken we allereerst Hibernate heeft de prijskolom gegenereerd met de niet nul beperking zoals we hadden verwacht.

Bovendien was het in staat om de SQL-invoegquery te maken en deze door te geven. Als resultaat, het is de onderliggende database die de fout heeft veroorzaakt.

4.1. Validatie

Bijna alle bronnen benadrukken dat @Column (nullable = false) wordt alleen gebruikt voor het genereren van DDL-schema's.

Slaapstand kan echter wel voer de validatie van de entiteit uit tegen het mogelijke nul waarden, zelfs als het overeenkomstige veld alleen is geannoteerd met @Column (nullable = false).

Om deze Hibernate-functie te activeren, moeten we de slaapstand.check_nullability eigendom aan waar:

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

Laten we nu onze testcase opnieuw uitvoeren en de uitvoer bekijken:

org.springframework.dao.DataIntegrityViolationException: eigenschap not-null verwijst naar een null of tijdelijke waarde: com.baeldung.h2db.springboot.models.Item.price; geneste uitzondering is org.hibernate.PropertyValueException: not-null eigenschap verwijst naar een null of tijdelijke waarde: com.baeldung.h2db.springboot.models.Item.price

Deze keer gooide onze testcase de org.hibernate.PropertyValueException.

Het is cruciaal om op te merken dat in dit geval Hibernate heeft de SQL-query voor invoegen niet naar de database verzonden.

5. Samenvatting

In dit artikel hebben we beschreven hoe de @Niet nul en @Column (nullable - false) annotaties werken.

Ook al verhinderen ze ons allebei om op te slaan nul waarden in de database, hebben ze verschillende benaderingen.

Als vuistregel, we zouden de voorkeur moeten geven aan de @Niet nul annotatie over de @Column (nullable = false) annotatie. Op deze manier zorgen we ervoor dat de validatie plaatsvindt voordat Hibernate SQL-query's voor invoegen of bijwerken naar de database verzendt.

Het is ook meestal beter te vertrouwen op de standaardregels die zijn gedefinieerd in de Bean Validation, in plaats van de database de validatielogica te laten afhandelen.

Maar zelfs als we Hibernate het databaseschema laten genereren, het vertaalt het @Niet nul annotatie in de databasebeperkingen. Daar moeten we dan alleen voor zorgen slaapstand.validator.apply_to_ddl eigenschap is ingesteld op waar.

Zoals gewoonlijk zijn alle codevoorbeelden beschikbaar op GitHub.