מחיקת אובייקטים במצב שינה

1. סקירה כללית

כמסגרת ORM מלאה, Hibernate אחראי על ניהול מחזור החיים של אובייקטים (ישויות) קבועים, כולל פעולות CRUD כגון לקרוא, לשמור, עדכון ו לִמְחוֹק.

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

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

2. דרכים שונות למחיקת אובייקטים

אובייקטים עשויים להימחק בתרחישים הבאים:

  • על ידי שימוש ב EntityManager. להסיר
  • כאשר מחיקה נפלת ממופעי ישות אחרים
  • כאשר an הסרת יתומים מוחל
  • על ידי ביצוע א לִמְחוֹק הצהרת JPQL
  • על ידי ביצוע שאילתות מקוריות
  • על ידי יישום טכניקת מחיקה רכה (סינון ישויות שנמחקו רכות לפי תנאי ב- @איפה סָעִיף)

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

3. מחיקה באמצעות מנהל הישויות

מחיקה עם EntityManager היא הדרך הכי פשוטה להסיר מופע של ישות:

פו פו = פו חדש ("פו"); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); assertThat (foo, notNullValue ()); entityManager.remove (foo); flushAndClear (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ()); 

בדוגמאות במאמר זה אנו משתמשים בשיטת עוזר לשטוף ולנקות את הקשר ההתמדה בעת הצורך:

void flushAndClear () {entityManager.flush (); entityManager.clear (); }

לאחר שהתקשר ל EntityManager. להסיר השיטה, המופע שסופק עובר ל- הוסר המחיקה הקשורה ממסד הנתונים מתרחשת בשטיפה הבאה.

ציין זאת מופע שנמחק נמשך מחדש אם א להתמיד הפעולה מוחלת עליו. טעות נפוצה היא להתעלם מכך ש להתמיד הפעולה הוחלה על מופע שהוסר (בדרך כלל מכיוון שהוא נפל ממופע אחר בזמן השטיפה) מכיוון שהקטע 3.2.2 לפי מפרט ה- JPA, נדרש להחזיק מקרה כזה שוב.

אנו ממחישים זאת על ידי הגדרת א @ManyToOne עמותה מ פו ל בָּר:

@Entity בכיתה ציבורית Foo {@ManyToOne (fetch = FetchType.LAZY, cascade = CascadeType.ALL) בר בר פרטי; // מיפויים אחרים, זוכים וקובעים}

כאשר אנו מוחקים א בָּר מופע שמפנה אליו א פו מופע אשר נטען גם בהקשר ההתמדה, בָּר מופע לא יוסר ממסד הנתונים:

סרגל בר = בר חדש ("בר"); פו פו = פו חדש ("פו"); foo.setBar (סרגל); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); bar = entityManager.find (Bar.class, bar.getId ()); entityManager.remove (סרגל); flushAndClear (); bar = entityManager.find (Bar.class, bar.getId ()); assertThat (סרגל, notNullValue ()); foo = entityManager.find (Foo.class, foo.getId ()); foo.setBar (null); entityManager.remove (סרגל); flushAndClear (); assertThat (entityManager.find (Bar.class, bar.getId ()), nullValue ());

אם הוסר בָּר מפנה על ידי א פו, ה להתמיד הפעולה נשמעת מ פו ל בָּר כי העמותה מסומנת ב מפל = CascadeType.ALL והמחיקה אינה מתוזמנת. כדי לוודא שזה קורה, אנו עשויים להפעיל רמת יומן מעקב עבור ה- אורג 'שינה חבילה וחפש ערכים כגון מחיקת ישות מבוטלת מתזמון.

4. מחיקה מדורגת

מחיקה יכולה להיות מדורגת לגופים ילדים כאשר ההורים מוסרים:

סרגל בר = בר חדש ("בר"); פו פו = פו חדש ("פו"); foo.setBar (סרגל); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); entityManager.remove (foo); flushAndClear (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ()); assertThat (entityManager.find (Bar.class, bar.getId ()), nullValue ());

פה בָּר מוסר מכיוון שההסרה מדורגת מ foo, מאחר שההתאחדות מוצהרת מדורגת את כל פעולות מחזור החיים מ פו ל בָּר.

ציין זאת זה כמעט תמיד חרק למפל לְהַסִיר פעולה בא @ManyToMany אִרגוּןמכיוון שזה יביא להסרת מופעי ילדים העלולים להיות קשורים למופעי הורה אחרים. זה חל גם על CascadeType.ALL, מכיוון שזה אומר שכל הפעולות צריכות להיות מדורגות, כולל לְהַסִיר מבצע.

5. הרחקת יתומים

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

אנו מראים זאת על ידי הגדרת עמותה כזו מ בָּר ל בז:

בר בכיתה ציבורית @Entity {@OneToMany (cascade = CascadeType.ALL, orphanRemoval = true) רשימה פרטית bazList = ArrayList חדש (); // מיפויים אחרים, זוכים וקובעים}

ואז א בז מופע נמחק באופן אוטומטי כאשר הוא מוסר מרשימת ההורה בָּר למשל:

סרגל בר = בר חדש ("בר"); באז באז = באז חדש ("בז"); bar.getBazList (). להוסיף (baz); entityManager.persist (bar); flushAndClear (); bar = entityManager.find (Bar.class, bar.getId ()); baz = bar.getBazList (). get (0); bar.getBazList (). remove (baz); flushAndClear (); assertThat (entityManager.find (Baz.class, baz.getId ()), nullValue ());

הסמנטיקה של הסרת יתומים הפעולה דומה לחלוטין ל- לְהַסִיר הפעולה מופעלת ישירות על מקרי הילד המושפעים, שפירושו ש- לְהַסִיר הפעולה נשמעת עוד יותר לילדים מקוננים. כתוצאה מכך, עליכם להבטיח כי אין מקרים אחרים המתייחסים למקרים שהוסרו (אחרת הם נמשכים מחדש).

6. מחיקה באמצעות הצהרת JPQL

Hibernate תומך בפעולות מחיקה בסגנון DML:

פו פו = פו חדש ("פו"); entityManager.persist (foo); flushAndClear (); entityManager.createQuery ("מחק מ- Foo שם id =: id") .setParameter ("id", foo.getId ()). executeUpdate (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ());

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

7. מחיקה באמצעות שאילתות מקוריות

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

פו פו = פו חדש ("פו"); entityManager.persist (foo); flushAndClear (); entityManager.createNativeQuery ("מחק מ- FOO שם ID =: id") .setParameter ("id", foo.getId ()). executeUpdate (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ());

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

8. מחיקה רכה

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

על מנת למנוע המון תנאים מיותרים ב איפה סעיפים בכל השאילתות שקוראות ישויות הניתנות למחיקה רכה, ה- Hibernate מספק את @איפה ביאור שניתן להציב על ישות ואשר מכיל קטע SQL שנוסף אוטומטית לשאילתות SQL שנוצרו עבור אותה ישות.

כדי להדגים זאת, אנו מוסיפים את @איפה ביאור ועמודה בשם נמחק אל ה פו יֵשׁוּת:

@Entity @Where (clause = "DELETED = 0") Foo class public Foo {// מיפויים אחרים @Column (name = "DELETED") שלם פרטי מחק = 0; // getters and setter public void setDeleted () {this.deleted = 1; }}

הבדיקה הבאה מאשרת שהכל עובד כצפוי:

פו פו = פו חדש ("פו"); entityManager.persist (foo); flushAndClear (); foo = entityManager.find (Foo.class, foo.getId ()); foo.setDeleted (); flushAndClear (); assertThat (entityManager.find (Foo.class, foo.getId ()), nullValue ());

9. מסקנה

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

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


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