תרדמת שינה @NotNull לעומת @Column (בטל = שקר)

1. הקדמה

במבט הראשון, זה אולי נראה כמו שניהם @לא ריק ו @Column (nullable = false) ביאורים משרתים את אותה מטרה וניתן להשתמש בהן לסירוגין. עם זאת, כפי שנראה בקרוב, זה לא לגמרי נכון.

למרות שכאשר משתמשים בישות JPA, שניהם למעשה מונעים אחסון ריק בערכים בבסיס הנתונים הבסיסי, ישנם הבדלים משמעותיים בין שתי הגישות הללו.

במדריך מהיר זה נשווה את ה- @לא ריק ו @Column (nullable = false) אילוצים.

2. תלות

עבור כל הדוגמאות המוצגות, נשתמש ביישום Spring Boot פשוט.

להלן קטע רלוונטי של pom.xml קובץ המציג תלות נחוצה:

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

2.1. ישות לדוגמא

בואו נגדיר ישות פשוטה מאוד בה נשתמש במהלך כל הדרכה זו:

פריט בכיתה ציבורית @Entity {@Id @GeneratedValue פרטי מזהה ארוך; מחיר פרטי BigDecimal; }

3. ה @לא ריק ביאור

ה @לא ריק ביאור מוגדר במפרט אימות השעועית. פירוש הדבר שהשימוש בו אינו מוגבל רק לגופים. להפך, אנחנו יכולים להשתמש @לא ריק גם על כל שעועית אחרת.

בואו להישאר עם מקרה השימוש שלנו ולהוסיף את @לא ריק ביאור ל פריטשל מחיר שדה:

פריט בכיתה ציבורית @Entity {@Id @GeneratedValue פרטי מזהה ארוך; מחיר מחירון BigDecimal פרטי לא; }

עכשיו, בואו ננסה להחזיק פריט עם ריקמחיר:

@SpringBootTest מחלקה ציבורית ItemIntegrationTest {@Autowired ItemRepository itemRepository; בטל ציבורי @Test צריך NotAllowToPersistNullItemsPrice () {itemRepository.save (פריט חדש ()); }}

ובואו נראה את הפלט של Hibernate:

2019-11-14 12: 31: 15.070 שגיאה 10980 --- [ראשי] ohiExceptionMapperStandardImpl: HHH000346: שגיאה במהלך שטיפה מנוהלת [אימות נכשל עבור שיעורים [com.baeldung.h2db.springboot.models.Item] במהלך זמן קבוע לקבוצות [javax.validation.groups.Default,] רשימת הפרות אילוצים: [ConstraintViolationImpl {interpolatedMessage = 'לא יכול להיות ריק', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]] (...) נגרם על ידי: javax.validation.ConstraintViolationException: אימות נכשל עבור שיעורים [com.baeldung.h2db.springboot.models.Item] במהלך זמן קבוע לקבוצות [javax.validation.groups.Default,] רשימת הפרות אילוצים: [ConstraintViolationImpl {interpolatedMessage = 'לא יכול להיות ריק', propertyPath = price, rootBeanClass = class com.baeldung.h2db.springboot.models.Item, messageTemplate = "{ javax.validation.constraints.NotNull.message} "}]

כמו שאנו יכולים לראות, במקרה זה המערכת שלנו זרקה javax.validation.ConstraintViolationException.

חשוב לשים לב כי מצב שינה לא הפעיל את הצהרת ההוספה של SQL. כתוצאה מכך, נתונים לא חוקיים לא נשמרו במסד הנתונים.

הסיבה לכך היא שאירוע מחזור החיים של הישות מראש התמיד לאימות השעועית ממש לפני שליחת השאילתה למסד הנתונים.

3.1. יצירת סכמות

בחלק הקודם הצגנו כיצד @לא ריק אימות עובד.

בואו נגלה עכשיו מה קורה אם אנחנו תן ל- Hibernate ליצור את סכימת מסד הנתונים עבורנו.

מסיבה זו, נקבע כמה מאפיינים שלנו application.properties קוֹבֶץ:

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

אם כעת נתחיל את היישום שלנו, נראה את הצהרת DDL:

צור פריט טבלה (id bigint לא null, מחיר עשרוני (19,2) לא null, מפתח ראשי (id))

למרבה ההפתעה, מצב שינה מוסיף באופן אוטומטי את לא ריק אילוץ ל מחיר הגדרת טור.

איך זה אפשרי?

כפי שמתברר, מחוץ לקופסה, Hibernate מתרגם את הערות אימות השעועית שהוחלו על הישויות למטא-נתונים של סכמת DDL.

זה די נוח והגיוני מאוד. אם אנו פונים @לא ריק לישות, קרוב לוודאי שאנחנו רוצים ליצור את עמודת מסד הנתונים המתאימה לא ריק גם כן.

עם זאת, אם, מכל סיבה שהיא, אנו רוצים כדי להשבית את התכונה 'שינה תרדמה', כל מה שאנחנו צריכים לעשות זה להגדיר hibernate.validator.apply_to_ddl נכס ל שֶׁקֶר.

על מנת לבדוק זאת בואו נעדכן את שלנו application.properties:

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

בואו נפעיל את היישום ונראה את הצהרת DDL:

צור פריט טבלה (id bigint לא null, מחיר עשרוני (19,2), מפתח ראשי (id))

כצפוי, הפעם שינה לא הוסיפה את לא ריק אילוץ ל מחיר טור.

4. ה @Column (nullable = false) ביאור

ה @טור ביאור מוגדר כחלק ממפרט ה- Java Persistence API.

הוא משמש בעיקר בדור המטא-נתונים של סכמת DDL. זה אומר ש אם נניח ל- Hibernate ליצור את סכימת מסד הנתונים באופן אוטומטי, היא מחילה את ה- לא ריק אילוץ לעמוד מסד הנתונים המסוים.

בואו נעדכן את שלנו פריט ישות עם @Column (nullable = false) וראה איך זה עובד בפעולה:

פריט בכיתה ציבורית @Entity {@Id @GeneratedValue פרטי מזהה ארוך; @Column (nullable = false) מחיר BigDecimal פרטי; }

כעת אנו יכולים לנסות להתמיד מחיר אפס ערך:

@SpringBootTest מחלקה ציבורית ItemIntegrationTest {@Autowired ItemRepository itemRepository; @Test הציבור בטל shouldNotAllowToPersistNullItemsPrice () {itemRepository.save (פריט חדש ()); }}

הנה קטע הפלט של Hibernate:

מצב שינה: צור פריט טבלה (id bigint לא null, מחיר עשרוני (19,2) לא null, מפתח ראשי (id)) (...) שינה: הכנס לערכי פריט (price, id) (?,?) 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 שגיאה 14580 --- [main ] ohengine.jdbc.spi.SqlExceptionHelper: NULL אסור לטור "PRICE"

ראשית, אנו יכולים להבחין בכך מצב שינה יצר את עמודת המחיר עם ה- לא ריק אילוץ כפי שציפינו.

בנוסף, היא הצליחה ליצור שאילתת הכנסת SQL ולהעביר אותה. כתוצאה, מסד הנתונים הבסיסי שהפעיל את השגיאה.

4.1. מַתַן תוֹקֵף

כמעט כל המקורות מדגישים זאת @Column (nullable = false) משמש רק לייצור סכמות DDL.

מצב שינה, לעומת זאת, מסוגל לבצע אימות של הישות כנגד האפשרי ריק ערכים, גם אם השדה המתאים מסומן רק עם @Column (nullable = false).

על מנת להפעיל תכונה זו במצב שינה, עלינו להגדיר במפורש את hibernate.check_nullability נכס ל נָכוֹן:

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

בוא נבצע שוב את מקרה הבדיקה ונבחן את התפוקה:

org.springframework.dao.DataIntegrityViolationException: המאפיין not-null מתייחס לערך null או חולף: com.baeldung.h2db.springboot.models.Item.price; חריג מקונן הוא org.hibernate.PropertyValueException: המאפיין not-null מפנה לערך null או חולף: com.baeldung.h2db.springboot.models.Item.price

הפעם, מקרה הבדיקה שלנו זרק את org.hibernate.PropertyValueException.

חשוב לשים לב שבמקרה זה, Hibernate לא שלח את שאילתת ה- SQL להכניס למסד הנתונים.

5. סיכום

במאמר זה תיארנו כיצד @לא ריק ו @Column (בטל - שקר) הערות עובדות.

למרות ששניהם מונעים מאיתנו לאחסן ריק ערכים במאגר, הם נוקטים גישות שונות.

ככלל אצבע, עלינו להעדיף את @לא ריק ביאור על @Column (nullable = false) ביאור. בדרך זו, אנו מוודאים שהאימות מתבצע לפני ש- Hibernate שולח שאילתות הוספה או עדכון SQL למסד הנתונים.

כמו כן, זה בדרך כלל עדיף להסתמך על הכללים הסטנדרטיים המוגדרים באימות השעועיתבמקום לתת למסד הנתונים לטפל בלוגיקת האימות.

אבל, גם אם נניח ל- Hibernate ליצור את סכימת מסד הנתונים, זה יתרגם את @לא ריק ביאור לאילוצי מסד הנתונים. עלינו רק לוודא זאת hibernate.validator.apply_to_ddl נכס מוגדר ל נָכוֹן.

כרגיל, כל דוגמאות הקוד זמינות ב- GitHub.


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