נעילה פסימית ב- JPA

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

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

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

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

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

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

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

אנו יכולים לרכוש מנעולים בלעדיים באמצעות 'בחר ... לעדכון' הצהרות.

2. מצבי נעילה

מפרט JPA מגדיר שלושה מצבי נעילה פסימיים שעליהם נדון:

  • PESSIMISTIC_READ - מאפשר לנו להשיג נעילה משותפת ולמנוע את עדכון הנתונים או מחיקתם של הנתונים
  • PESSIMISTIC_WRITE - מאפשר לנו להשיג נעילה בלעדית ולמנוע את קריאת הנתונים, עדכונם או מחיקתם
  • PESSIMISTIC_FORCE_INCREMENT - עובד כמו PESSIMISTIC_WRITE והיא מגדילה בנוסף תכונת גרסה של ישות עם גרסה

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

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

2.1. PESSIMISTIC_READ

בכל פעם שאנחנו רוצים פשוט לקרוא נתונים ולא להיתקל בקריאות מלוכלכות, נוכל להשתמש PESSIMISTIC_READ (נעילה משותפת). לא נוכל לבצע עדכונים או מחיקות.

לפעמים קורה שמאגר המידע בו אנו משתמשים אינו תומך ב- PESSIMISTIC_READ נעילה, כך שייתכן שנקבל את PESSIMISTIC_WRITE ננעל במקום.

2.2. PESSIMISTIC_WRITE

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

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

2.3. PESSIMISTIC_FORCE_INCREMENT

נעילה זו פועלת באופן דומה ל- PESSIMISTIC_WRITE, אך הוא הוצג כדי לשתף פעולה עם ישויות גרסאיות - ישויות שיש להן מאפיין המוענק @גִרְסָה.

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

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

2.4. חריגים

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

  • פסימי נעילת נעילה - מציין כי השגת נעילה או המרת משותף למנעול בלעדי נכשלת ומביאה להחזר ברמת העסקה
  • LockTimeoutException - מציין כי קבלת מנעול או המרת מנעול משותף לפסק זמן בלעדי ותוצאת החזר ברמת ההצהרה
  • חריג ההתנגדות - מציין כי התרחשה בעיה בהתמדה. חריגות התנגדות ותתי הסוגים שלה, למעט NoResultException, NonUniqueResultException,LockTimeoutException, ו QueryTimeoutException, מסמן את העסקה הפעילה שיש להחזיר לאחור.

3. שימוש במנעולים פסימיים

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

3.1. למצוא

זו כנראה הדרך הכי פשוטה. זה מספיק כדי לעבור LockModeType אובייקט כפרמטר ל- למצוא שיטה:

entityManager.find (Student.class, studentId, LockModeType.PESSIMISTIC_READ);

3.2. שאילתא

בנוסף, אנו יכולים להשתמש ב- שאילתא התנגד גם כן וקרא ל setLockMode מגדיר עם מצב נעילה כפרמטר:

שאילתת שאילתה = entityManager.createQuery ("מ- Student where studentId =: studentId"); query.setParameter ("studentId", studentId); query.setLockMode (LockModeType.PESSIMISTIC_WRITE); query.getResultList ()

3.3. נעילה מפורשת

אפשר גם לנעול ידנית את התוצאות שאוחזרו בשיטת החיפוש:

תלמיד resultStudent = entityManager.find (Student.class, studentId); entityManager.lock (resultStudent, LockModeType.PESSIMISTIC_WRITE);

3.4. לְרַעֲנֵן

אם אנו רוצים להחליף את מצב הישות על ידי ה- לְרַעֲנֵן שיטה, אנו יכולים גם להגדיר נעילה:

תלמיד resultStudent = entityManager.find (Student.class, studentId); entityManager.refresh (resultStudent, LockModeType.PESSIMISTIC_FORCE_INCREMENT);

3.5. NamedQuery

@NamedQuery ביאור מאפשר לנו להגדיר גם מצב נעילה:

@NamedQuery (name = "lockStudent", query = "SELECT s FROM Student s WHERE s.id LIKE: studentId", lockMode = PESSIMISTIC_READ)

4. היקף נעילה

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

כדי להגדיר את ההיקף שבו אנו יכולים להשתמש PessimisticLockScope enum. הוא מכיל שני ערכים: נוֹרמָלִי ו מורחב.

אנו יכולים להגדיר את ההיקף על ידי העברת פרמטר 'javax.persistance.lock.scope' עם PessimisticLockScope ערך כטיעון לשיטה הנכונה של EntityManager, שאילתא, TypedQuery אוֹ NamedQuery:

מאפייני מפה = HashMap חדש (); map.put ("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_WRITE, מאפיינים); 

4.1. PessimisticLockScope.NORMAL

עלינו לדעת כי PessimisticLockScope.NORMAL הוא היקף ברירת המחדל. עם היקף נעילה זה, אנו נועלים את היישות עצמה. כאשר משתמשים בו בירושה מחוברת הוא נועל גם את אבות הקדמונים.

בואו נסתכל על קוד הדוגמה עם שתי ישויות:

@Entity @Inheritance (אסטרטגיה = InheritanceType.JOINED) אדם בכיתה ציבורית {@ Id פרטי מזהה ארוך; שם מחרוזת פרטי; שם משפחה פרטי מחרוזת; // גטרים וקובעים} @Etity מעמד ציבורי עובד מאריך אדם {משכורת BigDecimal פרטית; // גטרים וקובעים}

כשאנחנו רוצים להשיג נעילה על עוֹבֵד, אנו יכולים לצפות ב SQL שאילתה המשתרעת על פני שתי הישויות הללו:

בחר t0.ID, t0.DTYPE, t0.LASTNAME, t0.NAME, t1.ID, t1.SALARY מאיש t0, עובד t1 היכן ((t0.ID =?) AND ((t1.ID = t0.ID) AND (t0.DTYPE =?))) לעדכון

4.2. PessimisticLockScope.EXDENDED

ה מורחב היקף מכסה את אותה פונקציונליות כמו נוֹרמָלִי. בנוסף, הוא מסוגל לחסום ישויות קשורות בטבלת הצטרפות.

במילים פשוטות, זה עובד עם ישויות שמסומנות עליהן @ElementCollection אוֹ @אחד לאחד, @אחד לרבים וכו 'עם @JoinTable.

בואו נסתכל על קוד הדוגמה עם ה- @ElementCollection ביאור:

לקוח @Entity ציבורי {@Id פרטי CustomerId ארוך; שם מחרוזת פרטי; שם משפחה פרטי מחרוזת; @ElementCollection @CollectionTable (name = "customer_address") כתובת רשימה פרטית; // getters and setters} @ Embeddable class class כתובת {מדינה מחרוזת פרטית; עיר מיתרים פרטית; // גטרים וקובעים}

בואו ננתח כמה שאילתות בעת חיפוש ה- צרכן יֵשׁוּת:

בחר לקוח, שם משפחה, שם מלקוח איפה (לקוח =?) לעדכון בחר עיר, מדינה, לקוח_לקוח ממסכת הלקוח איפה (לקוח_לקוח =?) לעדכון

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

עובדה מעניינת נוספת שעלינו להיות מודעים אליה היא שלא כל ספקי ההתמדה תומכים בהיקפי נעילה.

5. הגדרת פסק זמן לנעילה

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

אנו יכולים לשנות את ערך פסק הזמן באופן דומה לנעילת טווחים, באמצעות מאפיין 'javax.persistence.lock.timeout ' עם המספר המתאים של אלפיות השנייה.

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

מאפייני מפה = HashMap חדש (); map.put ("javax.persistence.lock.timeout", 1000L); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_READ, מאפיינים);

6. מסקנה

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

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

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

לבסוף, קוד המקור של הדרכה זו זמין ב- GitHub למצב שינה ול- EclipseLink.


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