Savepoint הוא סימנייה עם שם בתוך טרנזקציה
טרנזקציה רגילה היא הכול או כלום: כל מה שבין BEGIN ל-COMMIT נכנס יחד או נזרק יחד. בדרך כלל זה מה שרוצים, אבל לפעמים רוצים רזולוציה עדינה יותר: "נסו את קבוצת השינויים הזו, ואם משהו משתבש, בטלו רק אותה ותשאירו את שאר הטרנזקציה בחיים."
זה מה ש-savepoint עושה. מציבים סימנייה עם שם, עושים קצת עבודה, ואז או שומרים את העבודה (RELEASE) או חוזרים לסימנייה (ROLLBACK TO).
החיוב של Ada והזיכוי של Boris נשארים שניהם. העדכון השגוי ל-Nobody בוטל בלי לאבד את שאר הטרנזקציה.
שלוש הפקודות
שלוש פקודות הן כל ה-API:
SAVEPOINT name: הצבת סימנייה.RELEASE SAVEPOINT name: שמירת העבודה שנעשתה מאז הסימנייה, והסרת הסימנייה.ROLLBACK TO SAVEPOINT name: ביטול כל מה שנעשה מאז הסימנייה. הסימנייה נשארת במקומה כדי שאפשר יהיה לנסות שוב.
המילה SAVEPOINT אחרי RELEASE ואחרי ROLLBACK TO היא אופציונלית: גם RELEASE risky וגם ROLLBACK TO risky עובדות.
מבחינת מסד הנתונים הסופי, השורה step 2 attempt מעולם לא הייתה קיימת. כל השאר נכנס.
Savepoints בלי טרנזקציה חיצונית
הנה תפנית קטנה: אפשר להריץ SAVEPOINT בלי BEGIN לפני כן. SQLite פותחת בשקט טרנזקציה בשבילכם, וה-savepoint החיצוני ביותר משחק את התפקיד של הטרנזקציה עצמה. RELEASE על ה-savepoint הזה מבצע commit, ו-ROLLBACK TO חוזר אחורה בלי לבצע commit.
זו הסיבה ש-savepoints מתוארים לפעמים כ"טרנזקציות עם שם". אבל ערבוב של שני הסגנונות בקוד אמיתי מבלבל, אז בחרו אחד. רוב האנשים משתמשים ב-BEGIN ... COMMIT מפורש לגבול החיצוני, וב-savepoints רק לנקודות ביטול חלקיות בפנים.
קינון savepoints
Savepoints נערמים. אפשר להציב אחד בתוך אחר ולבטל את הפנימי בלי לגעת בחיצוני:
התוכן הסופי: a, b, d. החזרה ל-inner הסירה את c, אבל השאירה שלמה את העבודה שנעשתה לפני inner (ההכנסה של b), והטרנזקציה המשיכה.
חזרה ל-savepoint חיצוני זורקת גם את כל מה שנעשה ברמות הפנימיות: כל המחסנית שמעל השם הזה מתפרקת בבת אחת:
גם b וגם c נעלמו. ROLLBACK TO outer מחזיר אחורה את כל מה שנעשה מאז ש-outer הוצב, כולל inner וההכנסה של c.
למה להשתמש ב-savepoints?
המקרה הקלאסי הוא עיבוד של אצווה שבה מותר לפריטים בודדים להיכשל בלי לזרוק את כל האצווה. עטפו כל פריט ב-savepoint, ואם הוא נכשל, חזרו ל-savepoint והמשיכו הלאה:
בקוד אפליקציה אמיתי, ההכנסה הפגומה זורקת שגיאה, והאפליקציה תופסת אותה, מריצה ROLLBACK TO וממשיכה. שתי שורות תקינות נכנסות, והשורה הפגומה לא מרעילה את האצווה.
זה גם הדפוס שבו ORM וכלי מיגרציה מממשים טרנזקציות מקוננות: הם לא באמת מקננים בלוקים של BEGIN (ב-SQLite אי אפשר), הם ממפים קריאות מקוננות ל-savepoints.
כמה דברים שכדאי לשים לב אליהם
כמה פרטים שתופסים אנשים חדשים ב-savepoints:
COMMITתמיד מבצע commit לכל הטרנזקציה. לא משנה כמה savepoints פתוחים יש לכם:COMMIT(או הכינוי שלוEND) סוגר את כל הטרנזקציה החיצונית. אל תחשבו עלRELEASEכעל commit חלקי: שום דבר לא עמיד עד שהטרנזקציה העוטפת מבצעת commit.ROLLBACK(בליTO) מבטל הכול. הוא מסיים את הטרנזקציה וזורק את כל ה-savepoints הפתוחים. השתמשו ב-ROLLBACK TO nameכשאתם רוצים להשאיר את הטרנזקציה בחיים.- Savepoint נשאר פתוח עד שמשחררים אותו או חוזרים דרכו. אם שוכחים
RELEASEלא מאבדים נתונים, אבל הסימנייה פשוט נשארת שם עד שהטרנזקציה מסתיימת. - השמות לא חייבים להיות ייחודיים. אם מציבים
SAVEPOINT sפעמיים,ROLLBACK TO sמוצא את האחרון. שימושי לרקורסיה, מבלבל אם זה קרה בטעות.
הבא: Views
Savepoints נותנים שליטה עדינה יותר על כתיבות. השלב הבא הוא לעצב את האופן שבו קוראים: לשמור שאילתה כאובייקט עם שם שאפשר להשתמש בו שוב ולעשות ממנו SELECT כמו מטבלה. זה view, והוא הבא בתור.
שאלות נפוצות
מה זה savepoint ב-SQLite?
Savepoint הוא סמן עם שם שמציבים בתוך טרנזקציה. מאוחר יותר אפשר לעשות ROLLBACK TO לשם הזה כדי לבטל את כל מה שנעשה אחריו, או RELEASE כדי לשמור את השינויים ולהסיר את הסמן. Savepoints מאפשרים להתייחס לחלקים של טרנזקציה כיחידות קטנות יותר שאפשר להתאושש מהן.
מה ההבדל בין savepoint לטרנזקציה ב-SQLite?
טרנזקציה מתחילה ב-BEGIN ומסתיימת ב-COMMIT או ב-ROLLBACK. Savepoint מוצב בתוך טרנזקציה עם SAVEPOINT name ונותן נקודת ביטול חלקית. חזרה ל-savepoint לא מסיימת את הטרנזקציה העוטפת: אפשר להמשיך לעבוד ולבצע commit מאוחר יותר.
האם אפשר לקנן savepoints ב-SQLite?
כן. אפשר לערום savepoints עם שמות שונים, ו-ROLLBACK TO outer מבטל את כל מה שנעשה עד הרמה הזו, כולל savepoints פנימיים. השמות לא חייבים להיות ייחודיים: SQLite משתמשת ב-savepoint האחרון עם השם הזה, וזו התנהגות המחסנית הסטנדרטית.