Hibernate @NotNull vs @Column (nullable = false)

1. Uvod

Na prvi pogled, može se činiti kao oboje @NotNull i @Kolona (nullable = false) napomene imaju istu svrhu i mogu se koristiti naizmjenično. Međutim, kao što ćemo uskoro vidjeti, ovo nije potpuno točno.

Iako se, kada se koristi na JPA entitetu, obojica u biti sprečavaju skladištenje null vrijednosti u osnovnoj bazi podataka, postoje značajne razlike između ova dva pristupa.

U ovom brzom vodiču usporedit ćemo @NotNull i @Kolona (nullable = false) ograničenja.

2. Ovisnosti

Za sve predstavljene primjere koristit ćemo jednostavnu aplikaciju Spring Boot.

Evo relevantnog odjeljka pom.xml datoteka koja prikazuje potrebne ovisnosti:

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

2.1. Uzorak entiteta

Definirajmo također vrlo jednostavan entitet koji ćemo koristiti u ovom vodiču:

@Entity javna klasa Stavka {@Id @GeneratedValue private Long id; privatna cijena BigDecimal; }

3. The @NotNull Bilješka

The @NotNull napomena je definirana u specifikaciji provjere graha. To znači da njegova upotreba nije ograničena samo na entitete. Naprotiv, možemo koristiti @NotNull na bilo kojem drugom grahu.

Pridržimo se svog slučaja upotrebe i dodajte @NotNull bilješka na Artikal‘S cijena polje:

@Entity javna klasa Stavka {@Id @GeneratedValue private Long id; @NotNull privatna cijena BigDecimal; }

Pokušajmo sada zadržati stavku s nullcijena:

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

I pogledajmo izlaz Hibernate-a:

2019-11-14 12: 31: 15.070 POGREŠKA 10980 --- [glavna] ohiExceptionMapperStandardImpl: HHH000346: Pogreška tijekom upravljanog ispiranja [Provjera valjanosti nije uspjela za klase [com.baeldung.h2db.springboot.models.Item] tijekom trajanja vremena za grupe [javax.validation.groups.Default,] Popis kršenja ograničenja: [ConstraintViolationImpl {interpolatedMessage = 'ne smije biti null', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]] (...) Uzrok: javax.validation.ConstraintViolationException: Provjera valjanosti nije uspjela za klase [com.baeldung.h2db.springboot.models.Item] tijekom trajanja grupe [javax.validation.groups.Default,] Popis kršenja ograničenja: [ConstraintViolationImpl {interpolatedMessage = 'ne smije biti null', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]

Kao što vidimo, u ovom je slučaju naš sustav bacio javax.validation.ConstraintViolationException.

Važno je primijetiti da Hibernate nije pokrenuo SQL izjavu za umetanje. Slijedom toga, nevažeći podaci nisu spremljeni u bazu podataka.

To je zato što je događaj neprekidnog životnog ciklusa entiteta pokrenuo provjeru graha neposredno prije slanja upita u bazu podataka.

3.1. Generiranje sheme

U prethodnom smo odjeljku predstavili kako @NotNull provjera valjanosti.

Idemo sada saznati što će se dogoditi ako to učinimo neka Hibernate generira shemu baze podataka za nas.

Iz tog ćemo razloga postaviti nekoliko svojstava u našem primjena.svojstva datoteka:

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

Ako sada pokrenemo našu aplikaciju, vidjet ćemo DDL izjavu:

izradi stavku tablice (id bigint nije null, cijena decimal (19,2) nije null, primarni ključ (id))

Iznenađujuče, Hibernate automatski dodaje nije null ograničenje na cijena definicija stupca.

Kako je to moguće?

Kako se ispostavilo, Hibernate pretvara napomene o provjeri graha primijenjene na entitete u metapodatke DDL sheme.

Ovo je prilično povoljno i ima puno smisla. Ako se prijavimo @NotNull entitetu, najvjerojatnije želimo napraviti odgovarajući stupac baze podataka nije null također.

Međutim, ako iz bilo kojeg razloga želimo da bismo onemogućili ovu hibernaciju, sve što trebamo učiniti je postaviti hibernate.validator.apply_to_ddl svojstvo da lažno.

Da bismo ovo testirali, ažurirajmo naš primjena.svojstva:

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

Pokrenimo aplikaciju i pogledajte DDL izjavu:

izradi stavku tablice (id bigint nije null, cijena decimalna (19,2), primarni ključ (id))

Očekivano, ovaj put Hibernate nije dodao nije null ograničenje na cijena stupac.

4. The @Kolona (nullable = false) Bilješka

The @Stupac napomena je definirana kao dio specifikacije Java Persistence API.

Koristi se uglavnom u generiranju metapodataka DDL sheme. Ovo znači to ako dopustimo Hibernateu da automatski generira shemu baze podataka, primjenjuje se nije null ograničenje na određeni stupac baze podataka.

Ažurirajmo naš Artikal entitet s @Kolona (nullable = false) i pogledajte kako ovo djeluje na djelu:

@Entity javna klasa Stavka {@Id @GeneratedValue private Long id; @Kolona (nullable = false) privatna cijena BigDecimal; }

Sada možemo pokušati ustrajati a nula cijena vrijednost:

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

Evo isječka rezultata Hibernate-a:

Hibernate: izrada stavke tablice (id bigint nije null, cijena decimal (19,2) nije null, primarni ključ (id)) (...) Hibernate: umetanje u vrijednosti stavke (cijena, id) (?,?) 2019- 11-14 13: 23: 03.000 UPOZORENJE 14580 --- [glavna] ohengine.jdbc.spi.SqlExceptionHelper: SQL pogreška: 23502, SQLState: 23502 2019-11-14 13: 23: 03.000 GREŠKA 14580 --- [glavna ] ohengine.jdbc.spi.SqlExceptionHelper: NULL nije dopušteno za stupac "PRICE"

Prije svega, to možemo primijetiti Hibernate je generirao stupac cijene pomoću nije null ograničenje kakvo smo očekivali.

Uz to, uspio je stvoriti SQL upit za umetanje i proslijediti ga. Kao rezultat, pogreška je pokrenula osnovna baza podataka.

4.1. Provjera valjanosti

Gotovo svi izvori to ističu @ Stupac (nullable = false) koristi se samo za generiranje DDL sheme.

Hibernate, međutim, može izvršiti provjeru valjanosti entiteta u odnosu na moguće null vrijednosti, čak i ako je odgovarajuće polje označeno samo s @Kolona (nullable = false).

Da bismo aktivirali ovu značajku hibernacije, moramo izričito postaviti hibernate.check_nullability svojstvo da pravi:

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

Izvršimo sada naš testni slučaj i ispitajmo izlaz:

org.springframework.dao.DataIntegrityViolationException: svojstvo non-null odnosi se na nulu ili privremenu vrijednost: com.baeldung.h2db.springboot.models.Item.price; ugniježđena iznimka je org.hibernate.PropertyValueException: svojstvo not-null odnosi se na null ili privremenu vrijednost: com.baeldung.h2db.springboot.models.Item.price

Ovoga puta naš je test bacio org.hibernate.PropertyValueException.

Ključno je primijetiti da, u ovom slučaju, Hibernate nije poslao umetnuti SQL upit u bazu podataka.

5. Sažetak

U ovom smo članku opisali kako @NotNull i @Kolona (nullable - false) bilješke rade.

Iako nas obojica sprečavaju u pohrani null vrijednosti u bazi podataka, oni imaju različite pristupe.

U pravilu, trebali bismo preferirati @NotNull bilješka nad @Kolona (nullable = false) bilješka. Na taj način osiguravamo da se provjera valjanosti odvija prije nego što Hibernate pošalje bilo koji unos ili ažuriranje SQL upita u bazu podataka.

Također, obično je bolje se osloniti na standardna pravila definirana u provjeri graha, umjesto da dopušta bazi podataka da obrađuje logiku provjere valjanosti.

Ali, čak i ako pustimo Hibernate da generira shemu baze podataka, to će prevesti @NotNull napomena u ograničenja baze podataka. Tada to moramo samo osigurati hibernate.validator.apply_to_ddl svojstvo je postavljeno na pravi.

Kao i obično, svi primjeri koda dostupni su na GitHubu.


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