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.