התפשטות עסקאות ובידוד באביב @ Transactional
1. הקדמה
במדריך זה נסקור את @ Transactional ביאור שלה בידוד ו רְבִיָה הגדרות.
2. מה זה @ Transactional?
אנחנו יכולים להשתמש @ Transactional לעטוף שיטה בעסקת מסד נתונים.
זה מאפשר לנו לקבוע תנאי התפשטות, בידוד, פסק זמן, קריאה בלבד והחזר כספי לעסקה שלנו. כמו כן, אנו יכולים לציין את מנהל העסקאות.
2.1. @ Transactional פרטי היישום
Spring יוצר פרוקסי או מתפעל את קוד בת הכיתה כדי לנהל את היצירה, ההתחייבות וההחזר של העסקה. במקרה של מיופה כוח, ספרינג מתעלם @ Transactional בשיחות שיטה פנימיות.
במילים פשוטות, אם יש לנו שיטה כמו callMethod ואנחנו מסמנים את זה כ- @ Transactional, אביב יעטוף קוד ניהול של עסקאות סביב ההפעלה:@ Transactional שיטה הנקראת:
createTransactionIfNecessary (); נסה {callMethod (); commitTransactionAfterReturning (); } לתפוס (חריג) {completeTransactionAfterThrowing (); לזרוק חריג; }
2.2. איך להישתמש @ Transactional
אנו יכולים לשים את ההערה על הגדרות ממשקים, מחלקות או ישירות על שיטות. הם עוקפים זה את זה לפי סדר העדיפויות; מהנמוך לגבוה ביותר שיש לנו: ממשק, סופר קלאס, מחלקה, שיטת ממשק, שיטת סופר-קלאס ושיטת מחלקה.
אביב מיישם את ההערה ברמה הכיתתית על כל השיטות הציבוריות של הכיתה הזו שלא הערנו איתן @ Transactional .
עם זאת, אם נשים את ההערה על שיטה פרטית או מוגנת, אביב יתעלם ממנה ללא שגיאה.
נתחיל בדוגמת ממשק:
ממשק ציבורי @ Transactional TransferService {העברת חלל (משתמש מחרוזת 1, משתמש מחרוזת 2, שווי כפול); }
בדרך כלל, לא מומלץ להגדיר את @ Transactional על הממשק. עם זאת, זה מקובל במקרים כמו מאגר @ עם נתוני אביב.
אנו יכולים לשים את ההערה על הגדרת מחלקה כדי לעקוף את הגדרת העסקה של הממשק / סופר-קלאס:
@Service @Transactional public class TransferServiceImpl מיישם את TransferService {@ העברת חלל ריקים ציבורי (מחרוזת משתמש 1, מחרוזת משתמש 2, שווי כפול) {// ...}}
עכשיו בואו נעקוף אותו על ידי הגדרת ההערה ישירות על השיטה:
@ העברת חלל ציבורית ציבורי (מחרוזת משתמש 1, מחרוזת משתמש 2, ערך כפול) {// ...}
3. התפשטות עסקאות
ריבוי מגדיר את הגבול העסקה של ההיגיון העסקי שלנו. אביב מצליח להתחיל ולהשהות עסקה לפי שלנו רְבִיָה הגדרה.
אביב קורא TransactionManager :: getTransaction להשיג או ליצור עסקה בהתאם להתרבות. הוא תומך בחלק מהתפשטות לכל סוגי TransactionManager, אך ישנם כמה מהם שתומכים רק ביישומים ספציפיים של TransactionManager.
עכשיו בואו נעבור את ההפצות השונות וכיצד הם עובדים. נדרש הוא התפשטות ברירת המחדל. אביב בודק אם קיימת עסקה פעילה ואז הוא יוצר עסק חדש אם לא היה קיים דבר. אחרת, ההיגיון העסקי מצורף לעסקה הפעילה כרגע: גם כ נדרש הוא התפשטות ברירת המחדל, אנו יכולים לפשט את הקוד על ידי הפלתו: בואו נראה את קוד הפסאוד של אופן פעולת יצירת העסקאות נדרש רְבִיָה: ל תומכים, האביב בודק תחילה אם קיימת עסקה פעילה. אם קיימת עסקה, ישמש את העסקה הקיימת. אם אין עסקה, היא מבוצעת ללא עסקה: בואו נראה את קוד הפסאודו של יצירת העסקה עבור תומכים: כאשר ההפצה היא חובה, אם יש עסקה פעילה, היא תשמש אותה. אם אין עסקה פעילה, ספרינג מציג חריג: ובואו ונראה שוב את קוד הפסאודו: להיגיון עסקי עם לעולם לא התפשטות, אביב מעניק חריג אם יש עסקה פעילה: בואו נראה את קוד הפסאודו של האופן שבו פועלת יצירת עסקאות לעולם לא רְבִיָה: האביב משעה תחילה את העסקה הנוכחית אם היא קיימת, ואז ההיגיון העסקי מבוצע ללא עסקה. ה JTATransactionManager תומך בהשעיית עסקאות אמיתית מחוץ לקופסה. אחרים מדמים את ההשעיה על ידי החזקת הפניה לקיים ואז ניקוי מהקשר החוט כאשר ההפצה היא REQUIRES_NEW, אביב משעה את העסקה הנוכחית אם היא קיימת ואז יוצר עסק חדש: דומה ל אינו נתמך, אנחנו צריכים את JTATransactionManager להשעיית עסקה בפועל. והקוד הפסאודו נראה כך: ל מקונן התפשטות, אביב בודק אם קיימת עסקה, אז אם כן, זה מסמן נקודת שמירה. פירוש הדבר שאם ביצוע ההיגיון העסקי שלנו יוצא חריג, אזי החזרת עסקאות לנקודת החיסכון הזו. אם אין עסקה פעילה, זה עובד כמו נדרש . DataSourceTransactionManager תומך בהפצה זו מחוץ לקופסה. כמו כן, כמה יישומים של JTATransactionManager עשוי לתמוך בכך. JpaTransactionManager תומך מקונן רק לחיבורי JDBC. עם זאת, אם נקבע nestedTransactionAllowed דגל ל נָכוֹן, זה עובד גם עבור קוד גישה JDBC בעסקאות JPA אם מנהל ההתקן JDBC שלנו תומך בנקודות שמירה. לבסוף, בואו נקבע את רְבִיָה ל מקונן: בידוד הוא אחד המאפיינים הנפוצים של חומצה: אטומיות, עקביות, בידוד ועמידות. בידוד מתאר כיצד שינויים המופעלים על ידי עסקאות מקבילות גלויים זה לזה. כל רמת בידוד מונעת אפס או יותר תופעות לוואי במקביל לעסקה: אנו יכולים לקבוע את רמת הבידוד של עסקה לפי @ Transactional :: בידוד. יש בו חמש ספירות באביב: בְּרִירַת מֶחדָל, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, ניתן לסדר. רמת הבידוד המוגדרת כברירת מחדל היא בְּרִירַת מֶחדָל. לכן כאשר אביב יוצר עסקה חדשה, רמת הבידוד תהיה בידוד ברירת המחדל של ה- RDBMS שלנו. לכן עלינו להיזהר אם נשנה את מסד הנתונים. עלינו לשקול גם מקרים בהם אנו מכנים שרשרת של שיטות עם בידוד שונה. בתזרים הרגיל, הבידוד חל רק כאשר נוצרה עסקה חדשה. לפיכך אם מסיבה כלשהי איננו רוצים לאפשר שיטה לבצע בבידוד שונה, עלינו להגדיר TransactionManager :: setValidateExistingTransaction לאמיתי. ואז קוד הפסאודו לאימות העסקה יהיה: עכשיו בואו להעמיק ברמות בידוד שונות והשפעותיהן. READ_UNCOMMITTED היא רמת הבידוד הנמוכה ביותר ומאפשרת גישה בו זמנית ביותר. כתוצאה מכך הוא סובל משלוש תופעות הלוואי המקבילות. אז עסקה עם בידוד זה קוראת נתונים לא מחויבים של עסקאות מקבילות אחרות. כמו כן, הן קריאות שאינן ניתנות לחזרה והן קריאות פנטום יכולות לקרות. כך אנו יכולים לקבל תוצאה אחרת בקריאה חוזרת של שורה או ביצוע מחדש של שאילתת טווח. אנחנו יכולים להגדיר את בידוד רמה לשיטה או כיתה: Postgres אינו תומך READ_UNCOMMITTED בידוד ונופל חזרה ל במקום זאת, READ_COMMITED. כמו כן, אורקל אינה תומכת ומאפשרת READ_UNCOMMITTED. הרמה השנייה של בידוד, READ_COMMITTED, מונע קריאות מלוכלכות. שאר תופעות הלוואי במקביל עדיין יכולות לקרות. לכן לשינויים לא מחויבים בעסקאות מקבילות אין כל השפעה עלינו, אך אם עסקה תבצע את שינויים, התוצאה שלנו עשויה להשתנות על ידי שאילתות חוזרות. הנה, הגדרנו את בידוד רָמָה: READ_COMMITTED היא רמת ברירת המחדל עם Postgres, SQL Server ו- Oracle. הרמה השלישית של בידוד, REPEATABLE_READ, מונע קריאות מלוכלכות ולא חוזרות. כך שאיננו מושפעים משינויים בלתי מחויבים בעסקאות במקביל. כמו כן, כאשר אנו מבררים שוב שורה, אנו לא מקבלים תוצאה אחרת. אך בביצוע מחדש של שאילתות טווח, אנו עשויים לקבל שורות שנוספו או הוסרו לאחרונה. יתר על כן, זו הרמה הנמוכה ביותר הנדרשת כדי למנוע את העדכון האבוד. העדכון האבוד מתרחש כאשר שתי עסקאות מקבילות או יותר קוראות ומעדכנות את אותה שורה. REPEATABLE_READ אינו מאפשר גישה בו זמנית לשורה כלל. מכאן שהעדכון האבוד לא יכול לקרות. כך מגדירים את בידוד רמה לשיטה: REPEATABLE_READ היא רמת ברירת המחדל ב- Mysql. אורקל אינה תומכת REPEATABLE_READ. ניתן לסדר היא הרמה הגבוהה ביותר של בידוד. זה מונע את כל תופעות הלוואי המקבילות שהוזכרו, אך יכול להוביל לשיעור הגישה המקביל הנמוך ביותר מכיוון שהוא מבצע שיחות במקביל ברצף. במילים אחרות, ביצוע מקביל של קבוצה של עסקאות מסודרות יש את אותה תוצאה כמו ביצוען באופן סדרתי. עכשיו בואו נראה איך להגדיר ניתן לסדר כמו בידוד רָמָה: במדריך זה חקרנו את תכונת ההפצה של @עִסקָה בפירוט. לאחר מכן למדנו על תופעות לוואי במקביל ורמות בידוד. כמו תמיד, תוכל למצוא את הקוד השלם ב- GitHub.3.1. נדרש רְבִיָה
@Transactional (propagation = Propagation.REQUIRED) חלל ציבורי חובה לדוגמא (משתמש מחרוזת) {// ...}
@ חובה ציבורית ריקנית עסקית נדרשת לדוגמא (משתמש מחרוזת) {// ...}
if (isExistingTransaction ()) {if (isValidateExistingTransaction ()) {validateExisitingAndThrowExceptionIfNotValid (); } להחזיר את הקיים; } להחזיר createNewTransaction ();
3.2. תומכים רְבִיָה
@Transactional (propagation = Propagation.SUPPORTS) חלל ציבורי תומך לדוגמא (משתמש מחרוזת) {// ...}
if (isExistingTransaction ()) {if (isValidateExistingTransaction ()) {validateExisitingAndThrowExceptionIfNotValid (); } להחזיר את הקיים; } להחזיר ריק תנועה;
3.3. חובה רְבִיָה
@Transactional (propagation = Propagation.MANDATORY) ריק בטל חובה לדוגמא (משתמש מחרוזת) {// ...}
if (isExistingTransaction ()) {if (isValidateExistingTransaction ()) {validateExisitingAndThrowExceptionIfNotValid (); } להחזיר את הקיים; } לזרוק IllegalTransactionStateException;
3.4. לעולם לא רְבִיָה
@Transactional (propagation = Propagation.NEVER) חלל ציבורי neverExample (משתמש מחרוזת) {// ...}
אם (isExistingTransaction ()) {זרוק IllegalTransactionStateException; } החזר ריקTransaction;
3.5. אינו נתמך רְבִיָה
@Transactional (propagation = Propagation.NOT_SUPPORTED) חלל ציבורי notSupportedExample (משתמש מחרוזת) {// ...}
3.6. REQUIRES_NEW רְבִיָה
@Transactional (propagation = Propagation.REQUIRES_NEW) חלל ציבורי מחייב NewExample (משתמש מחרוזת) {// ...}
אם (isExistingTransaction ()) {להשעות (קיים); נסה {return createNewTransaction (); } לתפוס (חריג) {resumeAfterBeginException (); לזרוק חריג; }} להחזיר createNewTransaction ();
3.7. מקונן רְבִיָה
@Transactional (propagation = Propagation.NESTED) public void nestedExample (משתמש מחרוזת) {// ...}
4. בידוד עסקה
4.1. ניהול בידוד באביב
אם (isolationLevel! = ISOLATION_DEFAULT) {if (currentTransactionIsolationLevel ()! = isolationLevel) {throw IllegalTransactionStateException}}
4.2. READ_UNCOMMITTED בידוד
@Transactional (בידוד = בידוד. READ_UNCOMMITTED) יומן חלל ריק (הודעת מחרוזת) {// ...}
4.3. READ_COMMITTED בידוד
@Transactional (isolation = Isolation.READ_COMMITTED) יומן חלל ריק (הודעת מחרוזת) {// ...}
4.4. REPEATABLE_READ בידוד
@Transactional (isolation = Isolation.REPEATABLE_READ) יומן הריקים הציבורי (הודעת מחרוזת) {// ...}
4.5. ניתן לסדר בידוד
@Transactional (בידוד = Isolation.SERIALIZABLE) יומן ריק לציבור (הודעת מחרוזת) {// ...}
5. מסקנה