Hibernálás @NotNull vs @Column (nullable = false)

1. Bemutatkozás

Első pillantásra, úgy tűnhet, hogy mind a @Nem nulla és @ Oszlop (nullable = false) a kommentárok ugyanazt a célt szolgálják és felcserélhetően használható. Mint azonban hamarosan látni fogjuk, ez nem teljesen igaz.

Annak ellenére, hogy a JPA entitáson használják, mindkettő lényegében megakadályozza a tárolást nulla értékek az alapul szolgáló adatbázisban, jelentős különbségek vannak e két megközelítés között.

Ebben a gyors bemutatóban összehasonlítjuk a @Nem nulla és @ Oszlop (nullable = false) korlátok.

2. Függőségek

Az összes bemutatott példához egy egyszerű Spring Boot alkalmazást fogunk használni.

Itt található a pom.xml a szükséges függőségeket bemutató fájl:

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

2.1. Minta entitás

Határozzunk meg egy nagyon egyszerű entitást is, amelyet ebben az oktatóanyagban fogunk használni:

@Entity public class Item {@Id @GeneratedValue private Long id; privát BigDecimal ár; }

3. Az @Nem nulla Megjegyzés

A @Nem nulla az annotációt a Bean Validation specifikáció határozza meg. Ez azt jelenti, hogy a használata nem csak az entitásokra korlátozódik. Épp ellenkezőleg, használhatjuk @Nem nulla bármely más babon is.

Maradjunk mégis a használati esetünkön, és tegyük hozzá a @Nem nulla jegyzet a Tétel’S ár terület:

@Entity public class Item {@Id @GeneratedValue private Long id; @NotNull privát BigDecimal ár; }

Most próbáljunk meg egy elemet kitartani a-val nullaár:

@SpringBootTest public class ItemIntegrationTest {@Autowired private ItemRepository itemRepository; @Test public void shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (new Item ()); }}

Lássuk Hibernate kimenetét:

2019-11-14 12: 31: 15.070 ERROR 10980 --- [main] ohiExceptionMapperStandardImpl: HHH000346: Hiba a kezelt öblítés során [A validáció nem sikerült az osztályoknál (com.baeldung.h2db.springboot.models.Item] a csoportok tartós ideje alatt [javax.validation.groups.Default,] A korlátozások megsértésének listája: [ConstraintViolationImpl {interpolatedMessage = 'nem lehet null', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]] (...) okozta: javax.validation.ConstraintViolationException: A (z) [com.baeldung.h2db.springboot.models.Iem] osztályok érvényesítése sikertelen volt a csoportok tartós ideje alatt [javax.validation.groups.Default,] A korlátozások megsértésének listája: [ConstraintViolationImpl {interpolatedMessage = 'nem lehet null', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]

Ahogy látjuk, ebben az esetben a mi rendszerünk dobott javax.validation.ConstraintViolationException.

Fontos észrevenni, hogy a hibernálás nem váltotta ki az SQL insert utasítást. Következésképpen az érvénytelen adatokat nem mentették az adatbázisba.

Ennek oka az, hogy a pre-persist entitás életciklus eseménye közvetlenül a lekérdezés adatbázishoz való elküldése előtt váltotta ki a babellenőrzést.

3.1. Séma generálás

Az előző szakaszban bemutattuk, hogyan @Nem nulla validálás működik.

Nézzük meg, mi történik, ha mi hagyja, hogy a Hibernate generálja az adatbázis-sémát nekünk.

Emiatt beállítunk pár tulajdonságot a mi alkalmazás.tulajdonságok fájl:

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

Ha most elindítjuk az alkalmazásunkat, látni fogjuk a DDL utasítást:

táblázatelem létrehozása (id bigint nem null, ár decimális (19,2) nem null, elsődleges kulcs (id))

Meglepően, A hibernált állapot automatikusan hozzáadja a nem nulla kényszer a ár oszlopdefiníció.

Hogy lehetséges ez?

Ahogy kiderül, a dobozból a hibernálás lefordítja az entitásokra alkalmazott babellenőrzési kommentárokat a DDL séma metaadataira.

Ez nagyon kényelmes és sok értelme van. Ha alkalmazzuk @Nem nulla az entitáshoz valószínűleg a megfelelő adatbázis oszlopot szeretnénk elkészíteni nem nulla is.

Ha azonban valamilyen okból azt akarjuk ennek a hibernált funkciónak a letiltásához csak a beállítást kell tennünk hibernate.validator.apply_to_ddl tulajdonhoz hamis.

Ennek teszteléséhez frissítsük az újdonságokat alkalmazás.tulajdonságok:

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

Futtassuk az alkalmazást, és nézzük meg a DDL utasítást:

táblázatelem létrehozása (id bigint nem null, ár decimális (19,2), elsődleges kulcs (id))

A várakozásoknak megfelelően ezúttal Hibernate nem tette hozzá a nem nulla kényszer a ár oszlop.

4. A @ Oszlop (nullable = false) Megjegyzés

A @Oszlop az annotációt a Java Persistence API specifikáció részeként definiálják.

Főleg a DDL séma metaadatok generálásakor használják. Ez azt jelenti ha hagyjuk, hogy a Hibernate automatikusan létrehozza az adatbázis-sémát, akkor a nem nulla korlátozás az adott adatbázis oszlopra.

Frissítsük a Tétel entitás a @ Oszlop (nullable = false) és nézze meg, hogy ez hogyan működik:

@Entity public class Item {@Id @GeneratedValue private Long id; @ Oszlop (nullable = false) privát BigDecimal ár; }

Most megpróbálhatjuk kitartani a null ár érték:

@SpringBootTest public class ItemIntegrationTest {@Autowired private ItemRepository itemRepository; @Test public void shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (new Item ()); }}

Itt van a Hibernate kimenetének részlete:

Hibernálás: táblázatelem létrehozása (id bigint not null, price decimal (19,2) not null, primary key (id)) (...) Hibernate: insert to item (price, id) values ​​(?,?) 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 HIBA 14580 --- [main ] ohengine.jdbc.spi.SqlExceptionHelper: NULL nem engedélyezett a "PRICE" oszlopban

Először is észrevehetjük Hibernate létrehozta az ár oszlopot a nem nulla kényszer, amire számítottunk.

Ezenkívül képes volt létrehozni és továbbítani az SQL beszúrási lekérdezést. Ennek eredményeként ez a mögöttes adatbázis váltotta ki a hibát.

4.1. Érvényesítés

Szinte az összes forrás ezt hangsúlyozza @ Oszlop (nullable = false) csak a séma DDL előállításához használatos.

A hibernálás azonban képes végezze el az entitás hitelesítését a lehetségesekkel szemben nulla értékeket, még akkor is, ha a megfelelő mezőt csak @ Oszlop (nullable = false).

A hibernált funkció aktiválásához kifejezetten be kell állítanunk a hibernálás.ellenőrzés_kihasználatlanság tulajdonhoz igaz:

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

Vizsgáljuk meg újra a tesztesetet, és vizsgáljuk meg a kimenetet:

org.springframework.dao.DataIntegrityViolationException: a non-null tulajdonság null vagy tranziens értékre hivatkozik: com.baeldung.h2db.springboot.models.Item.price; a beágyazott kivétel az org.hibernate.PropertyValueException: a non-null tulajdonság null vagy tranziens értékre hivatkozik: com.baeldung.h2db.springboot.models.Item.price

Ezúttal tesztesetünk dobta a org.hibernate.PropertyValueException.

Rendkívül fontos észrevenni, hogy ebben az esetben A hibernálás nem küldte be az SQL beszúrási lekérdezést az adatbázisba.

5. Összefoglalás

Ebben a cikkben leírtuk, hogy a @Nem nulla és @ Oszlop (nullable - false) az annotációk működnek.

Annak ellenére, hogy mindkettő megakadályozza a tárolást nulla értékeket az adatbázisban, különböző megközelítéseket alkalmaznak.

Mint egy ökölszabály, inkább a @Nem nulla felirat a @ Oszlop (nullable = false) annotáció. Így megbizonyosodunk arról, hogy az érvényesítés még azelőtt megtörténik, hogy a Hibernate bármilyen beillesztési vagy frissítési SQL-kérdést elküldené az adatbázisba.

Továbbá általában jobb, ha a babellenőrzésben meghatározott szabványos szabályokra támaszkodunk, ahelyett, hogy az adatbázis kezelné az érvényesítési logikát.

De még ha hagyjuk is, hogy a Hibernate generálja az adatbázis sémát, lefordítja a @Nem nulla annotáció az adatbázis-korlátokba. Akkor csak arról kell gondoskodnunk hibernate.validator.apply_to_ddl tulajdonság értéke igaz.

Szokás szerint az összes kódpélda elérhető a GitHubon.